[TOC]java
使用數據庫是開發基本應用的基礎。藉助於開發框架,咱們已經不用編寫原始的訪問數據庫的代碼,也不用調用JDBC(Java Data Base Connectivity)或者鏈接池等諸如此類的被稱做底層的代碼,咱們將在高級的層次上訪問數據庫。而Spring Boot更是突破了之前全部開發框架訪問數據庫的方法,在史無前例的更加高級的層次上訪問數據庫。由於Spring Boot包含一個功能強大的資源庫,爲使用Spring Boot的開發者提供了更加簡便的接口進行訪問。mysql
提示: 能夠將Maven的中央倉庫修改成阿里雲的倉庫地址,加快jar包的加載速度。參考博文:Maven將中央倉庫修改成阿里雲的倉庫地址git
本章將介紹怎樣使用傳統的關係型數據庫,以及近期一段時間異軍突起的NoSQL(Not Only SQL)數據庫。程序員
本章的實例工程使用了分模塊的方式構建,各模塊的定義如表2-1所示。github
項目 | 工程 | 功能 |
---|---|---|
MySQL模塊 | mysql | 使用MySQL |
Redis模塊 | redis | 使用Redis |
MongoDB模塊 | mongodb | 使用MongoDB |
Neo4j模塊 | meo4j | 使用Neo4j |
提示:運行此實例須要從GitHub獲取源碼:https://github.com/shenhuanjie/spring-boot-db,並導入IDEA。web
對於傳統關係型數據庫來講,Spring Boot使用JPA(Java Persistence API)資源庫來實現對數據庫的操做,使用MySQL也是如此。簡單地說,JPA就是爲POJO(Plain Ordinary Java Object)提供持久化的標準規範,即將Java的普通對象經過對象關係映射(Object-Relational Mapping,ORM)持久化到數據庫中。redis
爲了使用JPA和MySQL,首先在工程中引入它們的Maven依賴,如代碼清單2-1所示。其中,指定了在運行時調用MySQL的依賴。spring
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-boot-db</artifactId> <groupId>springboot.db</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>mysql</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies> </project>
提示: 模塊pom.xml只需加上對應的引用便可,父級pom.xml則加上全局的spring.boot 引用。sql
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>springboot.db</groupId> <artifactId>spring-boot-db</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>mysql</module> <module>mongodb</module> <module>neo4j</module> <module>redis</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.2.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
首先建立一些普通對象,用來與數據庫的表創建映射關係,接着演示如何使用JPA對數據庫進行增刪改查等存取操做。mongodb
假如如今有三個實體:部門、用戶和角色,而且它們具備必定的關係,即一個用戶只能隸屬於一個部門,一個用戶能夠擁有多個角色。它們的關係模型如圖2-1所示。
Spring Boot的實體建模與使用Spring框架時的定義方法同樣,一樣比較方便的是使用了註解的方式來實現。
部門實體的建模如代碼清單2-2所示,其中註解@Table指定關聯的數據庫的表名,註解@Id定義一條記錄的惟一標識,並結合註解@GeneratedValue將其設置爲自動生成。部門實體只有兩個字段:id和name。程序中省略了Getter和Setter方法的定義,這些方法可使用IDEA的自動生成工具很方便地生成。
package dbdemo.mysql.entity; import javax.persistence.*; @Entity @Table(name = "department") public class Department { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; public Department() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
用戶實體包含三個字段:id、name和createdate,用戶實體建模如代碼清單2-3所示。其中註解@ManyToOne定義它與部門的多對一關係,而且在數據庫表中用字段did來表示部門的ID,註解@ManyToMany定義與角色實體的多對多關係,而且用中間表user_role來存儲它們各自的ID,以表示它們的對應關係。日期類型的數據必須使用註解@DateTimeFormat來進行格式化,以保證它在存取時能提供正確的格式,避免保存失敗。註解@JsonBackReference用來防止關係對象的遞歸訪問。
package dbdemo.mysql.entity; import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnore; import org.springframework.format.annotation.DateTimeFormat; import javax.persistence.*; import java.util.Date; import java.util.List; @Entity @Table(name = "user") public class User implements java.io.Serializable{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createdate; @ManyToOne @JoinColumn(name = "did") @JsonBackReference private Department deparment; @ManyToMany(cascade = {}, fetch = FetchType.EAGER) @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "roles_id")}) private List<Role> roles; public User() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getCreatedate() { return createdate; } public void setCreatedate(Date createdate) { this.createdate = createdate; } public Department getDeparment() { return deparment; } public void setDeparment(Department deparment) { this.deparment = deparment; } public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; } }
角色實體建模比較簡單,只要按設計的要求,定義id和name字段便可,固然一樣必須保證id的惟一性並將其設定爲自動生成。角色實體的建模如代碼清單2-4所示。
package dbdemo.mysql.entity; import javax.persistence.*; @Entity @Table(name = "role") public class Role implements java.io.Serializable{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; public Role() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
經過上面三個實體的定義,實現了使用Java的普通對象(POJO)與數據庫表創建映射關係(ORM),接下來使用JPA來實現持久化。
用戶實體使用JPA進行持久化的例子如代碼清單2-5所示。它是一個接口,並繼承於JPA資源庫JpaRepository接口,使用註解@Repository將這個接口也定義爲一個資源庫,使它能被其餘程序引用,併爲其餘程序提供存取數據庫的功能。
使用相同的方法,能夠定義部門實體和角色實體的資源庫接口。接口一樣繼承於JpaRepository接口,只要注意使用的參數是各自的實體對象便可。
package dbdemo.mysql.repository; import dbdemo.mysql.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.Date; import java.util.List; @Repository public interface UserRepository extends JpaRepository<User, Long> { User findByNameLike(String name); User readByName(String name); List<User> getByCreateddateLessThan(Date star); }
package dbdemo.mysql.repository; import dbdemo.mysql.entity.Department; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface DepartmentRepository extends JpaRepository<Department, Long> { }
package dbdemo.mysql.repository; import dbdemo.mysql.entity.Role; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface RoleRepository extends JpaRepository<Role, Long> { }
這樣就實現存取數據庫的功能了。如今能夠對數據庫進行增刪改查、進行分頁查詢和指定排序的字段等操做。
或許你還有疑問,咱們定義的實體資源庫接口並無聲明一個方法,也沒有對接口有任何實現的代碼,甚至一條SQL查詢語句都沒有寫,這怎麼可能?
是的,使用JPA就是能夠這麼簡單。咱們來看看JpaRepository的繼承關係,你也許會明白一些。如圖2-2所示,JpaRepository繼承於PagingAndSortingRepository,它提供了分頁和排序功能,PagingAndSortingRepository繼承於CrudRepository,它提供了簡單的增刪改查功能。
由於定義的接口繼承於JpaRepository,因此它傳遞性地繼承上面全部這些接口,並擁有這些接口的全部方法,這樣就不難理解爲什麼它包含那麼多功能了。這些接口提供的一些方法以下:
JPA還提供了一些自定義聲明方法的規則,例如,在接口中使用關鍵值findBy、readBy、getBy做爲方法名的前綴,拼接實體類中的屬性字段(首個字母大寫),並可選擇拼接一些SQL查詢關鍵字來組合成一個查詢方法。例如,對於用戶實體,下列查詢關鍵字能夠這樣使用:
又以下列對用戶實體類自定義的方法聲明,它們都是符合JPA規則的,這些方法也不用實現,JPA將會代理實現這些方法。
User findByNameLike(String name); User readByName(String name); List<User> getByCreateddateLessThan(Date star);
如今,爲了驗證上面設計的正確性,咱們用一個實例來測試一下。
首先,增長一個使用JPA的配置類,如代碼清單2-6所示。其中@EnableTransactionManagement啓用了JPA的事務管理;@EnableJpaRepositories啓用了JPA資源庫並制定了上面定義的接口資源庫的位置;@EntityScan指定了定義實體的位置,它將導入咱們定義的實體。注意,在測試時使用的JPA配置類可能與這個配置略有不一樣,這個配置的一些配置參數是從配置文件中讀取的,而測試時使用的配置類把一些配置參數都包含在類定義中了。
package dbdemo.mysql.config; import org.springframework.boot.orm.jpa.EntityScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.transaction.annotation.EnableTransactionManagement; @Order(Ordered.HIGHEST_PRECEDENCE) @Configuration @EnableTransactionManagement(proxyTargetClass = true) @EnableJpaRepositories(basePackages = "dbdemo.**.repository") @EntityScan(basePackages = "dbdemo.**.entity") public class JpaConfiguration { @Bean PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){ return new PersistenceExceptionTranslationPostProcessor(); } }
其次,在MySQL數據庫服務器中建立一個數據庫test,而後配置一個能夠訪問這個數據庫的用戶及其密碼。數據庫的表結構能夠不用建立,在程序運行時將會按照實體的定義自動建立。若是尚未建立一個具備徹底權限訪問數據庫test的用戶,能夠在鏈接MySQL服務器的查詢窗口中執行下面指令,這個指令假設你將在本地中訪問數據庫。
grant all privileges on test.* to 'root'@'localhost' identified by '123456';
而後,在Spring Boot的配置文件application.yml中使用如代碼清單2-7所示的配置,用來設置數據源和JPA的工做模式。
spring: datasource: url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8 username: root password: 12345678 jpa: database: MYSQL show-sql: true #Hibernate ddl auto (validate|create|create-drop|update) hibernate: ddl-auto: update naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy properties: hibernate: dialect: org.hibernate.dialect.MySQL5Dialect
配置中將ddl-auto設置爲update,就是使用Hibernate來自動更新表結構的,即若是數據表不存在則建立,或者若是修改了表結構,在程序啓動時則執行表結構的同步更新。
最後,編寫一個測試程序,如代碼清單2-8所示。測試程序首先初始化數據庫,建立一個部門,命名爲「開發部」,建立一個角色,命名爲admin,建立一個用戶,命名爲user,同時將它所屬部門設定爲上面建立的部門,並將現有的全部角色都分配給這個用戶。而後使用分頁的方式查詢全部用戶的列表,並從查到的用戶列表中,打印出用戶的名稱、部門的名稱和第一個角色的名稱等信息。
package dbdemo.mysql.test; import dbdemo.mysql.entity.Department; import dbdemo.mysql.entity.Role; import dbdemo.mysql.entity.User; import dbdemo.mysql.repository.DepartmentRepository; import dbdemo.mysql.repository.RoleRepository; import dbdemo.mysql.repository.UserRepository; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Assert; import java.util.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {JpaConfiguration.class}) public class MysqlTest { private static Logger logger = LoggerFactory.getLogger(MysqlTest.class); @Autowired UserRepository userRepository; @Autowired DepartmentRepository departmentRepository; @Autowired RoleRepository roleRepository; @Before public void initData(){ userRepository.deleteAll(); roleRepository.deleteAll(); departmentRepository.deleteAll(); Department department = new Department(); department.setName("開發部"); departmentRepository.save(department); Assert.notNull(department.getId()); Role role = new Role(); role.setName("admin"); roleRepository.save(role); Assert.notNull(role.getId()); User user = new User(); user.setName("user"); user.setCreatedate(new Date()); user.setDeparment(department); List<Role> roles = roleRepository.findAll(); Assert.notNull(roles); user.setRoles(roles); userRepository.save(user); Assert.notNull(user.getId()); } @Test public void findPage(){ Pageable pageable = new PageRequest(0, 10, new Sort(Sort.Direction.ASC, "id")); Page<User> page = userRepository.findAll(pageable); Assert.notNull(page); for(User user : page.getContent()) { logger.info("====user==== user name:{}, department name:{}, role name:{}", user.getName(), user.getDeparment().getName(), user.getRoles().get(0).getName()); } } }
**提示:**test目錄下一樣加入JpaConfiguration配置類
package dbdemo.mysql.test; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.support.TransactionTemplate; import javax.sql.DataSource; import java.util.Properties; @Configuration @EnableJpaRepositories(basePackages = "dbdemo.**.repository") public class JpaConfiguration { @Bean PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){ return new PersistenceExceptionTranslationPostProcessor(); } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test?characterEncoding=utf8"); dataSource.setUsername("root"); dataSource.setPassword("123456"); return dataSource; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource()); entityManagerFactoryBean.setPackagesToScan("dbdemo.mysql.entity"); entityManagerFactoryBean.setJpaProperties(buildHibernateProperties()); entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter() {{ setDatabase(Database.MYSQL); }}); return entityManagerFactoryBean; } protected Properties buildHibernateProperties() { Properties hibernateProperties = new Properties(); hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"); hibernateProperties.setProperty("hibernate.show_sql", "true"); hibernateProperties.setProperty("hibernate.use_sql_comments", "false"); hibernateProperties.setProperty("hibernate.format_sql", "true"); hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update"); hibernateProperties.setProperty("hibernate.generate_statistics", "false"); hibernateProperties.setProperty("javax.persistence.validation.mode", "none"); //Audit History flags hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", "true"); hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", "true"); return hibernateProperties; } @Bean public PlatformTransactionManager transactionManager() { return new JpaTransactionManager(); } @Bean public TransactionTemplate transactionTemplate() { return new TransactionTemplate(transactionManager()); } }
好了,如今可使用JUnit來運行這個測試程序了,在IDEA的Run/Debug Configuration配置中增長一個JUnit配置項,模塊選擇mysql,工做目錄選擇模塊所在的根目錄,程序選擇dbdemo.mysql.test.MysqlTest,並將配置項目名稱保存爲mysqlTest,如圖2-3所示。
用Debug方式運行測試配置項目mysqltest,能夠在控制檯中看到執行的過程和結果。若是狀態欄中顯示爲綠色,而且提示「All Tests passed」,則表示測試所有經過。在控制檯中也能夠查到下列打印信息:
dbdemo.mysql.test.MysqlTest - ====user==== ,user name:user,department name:開發部,role name:admin
這時若是在MySQL服務器中查看數據庫test,不但能夠看到表結構都已經建立了,還能夠看到上面測試生成的一些數據。
這是否是很激動人心?在Spring Boot使用數據庫,就是能夠如此簡單和有趣。到目前爲止,咱們不只沒有寫過一條查詢語句,也沒有實現一個訪問數據庫的方法,可是已經能對數據庫執行全部的操做,包括通常的增刪改查和分頁查詢。
關係型數據庫在性能上老是存在一些這樣那樣的缺陷,因此你們有時候在使用傳統關係型數據庫時,會與具備高效存取功能的緩存系統結合使用,以提升系統的訪問性能。在不少流行的緩存系統中,Redis是一個不錯的選擇。Redis是一種能夠持久存儲的緩存系統,是一個高性能的key-value數據庫,它使用鍵-值對的方式來存儲數據。
須要使用Redis,可在工程的Maven配置中加入spring-boot-starter-redis依賴,如代碼清單2-9所示。其中gson是用來轉換Json數據格式的工具,mysql是引用了上一節的模塊,這裏使用2.1節定義的實體對象來存取數據,演示Redis中的存取操做。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-boot-db</artifactId> <groupId>springboot.db</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>redis</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.2.4</version> </dependency> <dependency> <groupId>springboot.db</groupId> <artifactId>mysql</artifactId> <version>${project.version}</version> </dependency> </dependencies> </project>
Redis提供了下列幾種數據類型可供存取:
在實例中,將使用string即字符串類型來演示數據的存取操做。對於Redis,Spring Boot沒有提供像JPA那樣相應的資源庫接口,因此只能仿照上一節中Repository的定義編寫一個實體User的服務類,如代碼清單2-10所示。這個服務類能夠存取對象User以及由User組成的列表List,同時還提供了一個刪除的方法。全部這些方法都是使用RedisTemplate來實現的。
package dbdemo.redis.repository; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import dbdemo.mysql.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; import org.springframework.util.StringUtils; import java.util.List; import java.util.concurrent.TimeUnit; @Repository public class UserRedis { /** * 這些方法都是使用RedisTemplate來實現的。 */ @Autowired private RedisTemplate<String, String> redisTemplate; /** * Add User * * @param key * @param time * @param user */ public void add(String key, Long time, User user) { Gson gson = new Gson(); redisTemplate.opsForValue().set(key, gson.toJson(user), time, TimeUnit.MINUTES); } /** * Add User List * * @param key * @param time * @param users */ public void add(String key, Long time, List<User> users) { Gson gson = new Gson(); redisTemplate.opsForValue().set(key, gson.toJson(users), time, TimeUnit.MINUTES); } /** * Get User * * @param key * @return */ public User get(String key) { Gson gson = new Gson(); User user = null; String userJson = redisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(userJson)) user = gson.fromJson(userJson, User.class); return user; } /** * Get User List * * @param key * @return */ public List<User> getList(String key) { Gson gson = new Gson(); List<User> ts = null; String listJson = redisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(listJson)) ts = gson.fromJson(listJson, new TypeToken<List<User>>() { }.getType()); return ts; } /** * Delete Obj * * @param key */ public void delete(String key) { redisTemplate.opsForValue().getOperations().delete(key); } }
Redis沒有表結構的概念,因此要實現MySQL數據庫中表的數據(即普通Java對象映射的實體數據)在Redis中存取,必須作一些轉換,使用JSON格式的文本做爲Redis與Java普通對象互相交換數據的存儲格式。這裏使用Gson工具將類對象轉換爲JSON格式的文本進行存儲,要取出數據時,再將JSON文本轉化爲Java對象。
由於Redis使用key-value的方式存儲數據,因此存入時要生成一個惟一的key,而要查詢或刪除數據時,就可使用這個惟一的key進行相應的操做。
保存在Redis數據庫中的數據默認是永久存儲的,能夠指定一個時限來肯定數據的生命週期,超過指定時限的數據將被Redis自動清除。在代碼清單2-10中咱們以分鐘爲單位設定了數據的存儲期限。
另外,爲了能正確調用RedisTemplate,必須對其進行一些初始化工做,即主要對它存取的字符串進行一個JSON格式的系列化初始配置,如代碼清單2-11所示。
package dbdemo.redis.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, String> redisTemplate( RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
若是尚未按照Redis服務器,能夠參照本書附錄C提供的方法安裝,而後在工程的配置文件application.yml中配置鏈接Redis服務器等參數,如代碼清單2-12所示。其中host和port分別表示Redis數據庫服務器的IP地址和開放端口,database能夠不用指定,由Redis根據存儲狀況自動選定(注:測試時這些配置是集中在一個配置類中實現的)。
spring: redis: # database: 1 host: 127.0.0.1 port: 6379 pool: max-idle: 8 min-idle: 0 max-active: 8 max-wait: -1
如今編寫一個JUnit測試程序,來演示如何在Redis服務器中存取數據,如代碼清單2-13所示。測試程序建立一個部門對象並將其命名爲「開發部」,建立一個角色對象並把它命名爲admin,建立一個用戶對象並把它命名爲user,同時設定這個用戶屬於「開發部」,並把admin這個角色分配給這個用戶。接着測試程序使用類名等參數生成一個key,並使用這個key清空原來的數據,而後用這個key存儲如今這個用戶的數據,最後使用這個key查詢用戶,並將查到的信息打印出來。
package dbdemo.redis.test; import dbdemo.mysql.entity.Department; import dbdemo.mysql.entity.Role; import dbdemo.mysql.entity.User; import dbdemo.redis.repository.UserRedis; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Assert; import java.util.ArrayList; import java.util.Date; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {RedisConfig.class, UserRedis.class}) public class RedisTest { private static Logger logger = LoggerFactory.getLogger(RedisTest.class); @Autowired UserRedis userRedis; @Before public void setup() { Department department = new Department(); department.setName("開發部"); Role role = new Role(); role.setName("admin"); User user = new User(); user.setName("user"); user.setCreatedate(new Date()); user.setDepartment(department); List<Role> roles = new ArrayList<>(); roles.add(role); user.setRoles(roles); userRedis.delete(this.getClass().getName() + ":userByName:" + user.getName()); userRedis.add(this.getClass().getName() + ":userByName:" + user.getName(), 10L, user); } @Test public void get() { User user = userRedis.get(this.getClass().getName() + ":userByName:user"); Assert.notNull(user); logger.info("======user====== name:{}, department:{}, role:{}", user.getName(), user.getDepartment().getName(), user.getRoles().get(0).getName()); } }
**提示:**可使用RedisStudio進行可視化監控
要運行這個測試程序,能夠在IDEA的Run/Debug Configuration配置中增長一個JUnit配置項目,模塊選擇redis,工做目錄選擇模塊所在的根目錄,類選擇這個測試程序即dbdemo.redis.test.RedisTest,並將配置保存爲redistest。
使用Debug方式運行測試項目redistest。若是測試經過,會輸出一個用戶的用戶名、所屬部門和擁有角色等簡要信息,以下所示:
INFO dbdemo.redis.test.RedisTest - ======user====== name:user, department:開發部, role:admin
對於Redis的使用,還能夠將註解方式與調用數據庫的方法相結合,那樣就不用再編寫像上面那樣的服務類,而且使用起來更加簡單,這將在後面的章節中介紹。
在當前流行的NoSQL數據庫中,MongoDB是你們接觸比較早並且用得比較多的數據庫。MongoDB是文檔型的NoSQL數據庫,具備大數據量、高併發等優點,但缺點是不能創建實體關係,並且也沒有事務管理機制。
在Spring Boot中使用MongoDB也像使用JPA同樣容易,而且一樣擁有功能完善的資源庫。一樣的,要使用MongoDB,首先必須在工程的Maven中引入它的依賴,如代碼清單2-14所示。除了MongoDB自己的依賴以外,還須要一些附加的工具配套使用。
<dependencies> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.pegdown</groupId> <artifactId>pegdown</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-hateoas</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> </dependency> </dependencies>
MongoDB是文檔型數據庫,使用MongoDB也能夠像使用關係型數據庫那樣爲文檔建模。如代碼清單2-15所示,爲用戶文檔建模,它具備用戶名、密碼、用戶名稱、郵箱和註冊日期等字段,有一個用來保存用戶的數據集,還定義了一個構造函數,能夠很方便地用來建立一個用戶實例。
package dbdemo.mongo.models; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; import javax.validation.constraints.NotNull; import java.util.Date; import java.util.HashSet; import java.util.Set; @Document(collection = "user") public class User { @Id private String userId; @NotNull @Indexed(unique = true) private String username; @NotNull private String password; @NotNull private String name; @NotNull private String email; @NotNull private Date registrationDate = new Date(); private Set<String> roles = new HashSet<>(); public User() { } @PersistenceConstructor public User(String userId, String username, String password, String name, String email, Date registrationDate, Set<String> roles) { this.userId = userId; this.username = username; this.password = password; this.name = name; this.email = email; this.registrationDate = registrationDate; this.roles = roles; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Date getRegistrationDate() { return registrationDate; } public void setRegistrationDate(Date registrationDate) { this.registrationDate = registrationDate; } public Set<String> getRoles() { return roles; } public void setRoles(Set<String> roles) { this.roles = roles; } @Override public String toString() { return "User{" + "userId=" + userId + ", username='" + username + '\'' + ", password='" + password + '\'' + ", name='" + name + '\'' + ", email='" + email + '\'' + ", registrationDate=" + registrationDate + ", roles=" + roles + '}'; } }
MongoDB也有像使用JPA那樣的資源庫,如代碼清單2-16所示,爲用戶文檔建立了一個Repository接口,繼承於MongoRepository,實現了文檔持久化。
package dbdemo.mongo.repositories; import dbdemo.mongo.models.User; import org.springframework.data.mongodb.repository.MongoRepository; public interface UserRepository extends MongoRepository<User, String> { User findByUsername(String username); }
MongoRepository的繼承關係如圖2-4所示,看起來跟JPA的資源庫的繼承關係沒有什麼兩樣,它也包含訪問數據庫的豐富功能。
代碼清單2-17是用在測試中的使用MongoDB的一個配置類定義,其中@PropertySource指定讀取數據庫配置文件的位置和名稱,@EnableMongoRepositories啓用資源庫並設定定義資源庫接口放置的位置,這裏使用環境變量Environment來讀取配置文件的一些數據庫配置參數,而後使用一個數據庫客戶端,鏈接MongoDB服務器。
package dbdemo.mongo.test; import com.mongodb.Mongo; import com.mongodb.MongoClient; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.data.mongodb.config.AbstractMongoConfiguration; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; import java.util.ArrayList; import java.util.List; @Configuration @EnableMongoRepositories(basePackages = "dbdemo.mongo.repositories") @PropertySource("classpath:test.properties") public class TestDataSourceConfig extends AbstractMongoConfiguration { @Autowired private Environment env; @Override public String getDatabaseName() { return env.getRequiredProperty("mongo.name"); } @Override @Bean public Mongo mongo() throws Exception { ServerAddress serverAddress = new ServerAddress(env.getRequiredProperty("mongo.host")); List<MongoCredential> credentials = new ArrayList<>(); return new MongoClient(serverAddress, credentials); } }
若是尚未安裝MongoDB服務器,能夠參照附錄B的方法安裝並啓動一個Mon共DB服務器。而後,使用如代碼清單2-18所示的配置方法配置鏈接服務器的一些參數,該配置假定你的MongoDB服務器安裝在本地,並使用默認的數據庫端口:27017。
# MongoDB mongo.username=test mongo.password=test mongo.host=localhost mongo.name=test mongo.port=27017
這樣就能夠編寫一個JUnit測試例子來測試UserRepository接口的使用狀況,如代碼清單2-19所示。測試例子首先使用用戶文檔類建立一個用戶對象實例,而後使用資源接口調用save方法將用戶對象保存到數據庫中,最後使用findAll方法查詢全部用戶的列表,並使用一個循環輸出用戶的簡要信息。
package dbdemo.mongo.test; import dbdemo.mongo.models.User; import dbdemo.mongo.repositories.UserRepository; import org.junit.Before; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Assert; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestDataSourceConfig.class}) @FixMethodOrder public class RepositoryTests { private static Logger logger = LoggerFactory.getLogger(RepositoryTests.class); @SuppressWarnings("SpringJavaAutowiringInspection") @Autowired UserRepository userRepository; @Before public void setup() { Set<String> roles = new HashSet<>(); roles.add("manage"); User user = new User("1", "user", "12345678", "name", "email@com.cn", new Date(), roles); userRepository.save(user); } @Test public void findAll() { List<User> users = userRepository.findAll(); Assert.notNull(users); for (User user : users) { logger.info("===user=== userid:{}, username:{}, pass:{}, registrationDate:{}", user.getUserId(), user.getName(), user.getPassword(), user.getRegistrationDate()); } } } // > db.user.find() // { "_id" : "1", "_class" : "dbdemo.mongo.models.User", "username" : "user", "pass // word" : "12345678", "name" : "name", "email" : "email@com.cn", "registrationDate // " : ISODate("2016-04-13T06:27:02.423Z"), "roles" : [ "manage" ] }
如今能夠在IDEA的Run/Debug Configuration配置中增長一個JUnit測試項目,模塊選擇mongodb,工做目錄選擇模塊所在的工程根目錄,類選擇上面編寫的測試例子,即dbdemo.mongo.test.RepositoryTests,並將配置保存爲mongotest。
使用Debug方式運行測試項目mongotest。若是經過測試,將輸出查到的用戶的簡要信息,以下所示:
dbdemo.mongo.test.RepositoryTests - ===user=== userid:1, username:name, pass:12345678, registrationDate: Tue Jun 07 14:26:02 CST 2016
這時使用MongoDB數據庫客戶端輸入下面的查詢指令,也能夠查到這條文檔的詳細信息,這是一條JSON結構的文本信息。
> db.user.find() { "_id" : "1", "_class" : "dbdemo.mongo.models.User", "username" : "user", "password" : "12345678", "name" : "name", "email" : "email@com.cn", "registrationDate", ISODate("2016-04-13T06:27:02.423Z"), "roles" : ["mange"] }
有沒有既具備傳統關係型數據庫的優勢,又具有NoSQL數據庫優點的一種數據庫呢?Neo4j就是一種這樣的數據庫。Neo4j是一個高性能的NoSQL圖數據庫,而且具有徹底事務特性。Neo4j將結構化數據存儲在一張圖上,圖中每個結點的屬性表示數據的內容,每一條有向邊表示數據的關係。Neo4j沒有表結構的概念,它的數據用結點的屬性來表示。
在Spring Boot中使用Neo4j很是容易,由於有spring-data-neo4j提供了強大的支持。首先,在工程的Maven管理中引入Neo4j的相關依賴,如代碼清單2-20所示。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-neo4j</artifactId> <version>4.0.0.RELEASE</version> </dependency> <dependency> <groupId>com.voodoodyne.jackson.jsog</groupId> <artifactId>jackson-jsog</artifactId> <version>1.1</version> <scope>compile</scope> </dependency> </dependencies>
雖然Neo4j沒有表結構的概念,但它有結點和關係的概念。例如,如今有演員和電影兩個實體,它們的關係表現爲一個演員在一部電影中扮演一個角色。那麼就能夠建立演員和電影兩個節點實體,和一個角色關係實體。它們的實體-關係模型如圖2-5所示。這個實體-關係模型的定義比起關係型數據庫的實體-關係模型的定義要簡要得多,可是它更加形象和貼切地表現了實體之間的關係。更難能難得的是,這個實體-關係模型是能夠不通過任何轉換而直接存入數據庫的,也就是說,在Neo4j圖數據庫中保存的數據與圖2-5所示的相同,它仍然是一張圖。這對於業務人員和數據庫設計人員來講,它的意義相同。因此使用Neo4j數據庫,將在很大程度上減輕了設計工做和溝通工做。
像JPA使用了ORM意義,Neo4j使用了對象-圖形映射(Object-Graph Mapping,OGM)的方式來建模。代碼清單2-21是演員節點實體建模,使用註解@JsonIdentityInfo是防止查詢數據庫時引起遞歸訪問效應,註解@NodeEntity標誌這個類是一個節點實體,註解@GraphId定義了節點的一個惟一性標識,它將在建立結點時由系統自動生成,因此它是不可缺乏的。這個節點預約義了其餘兩個屬性,name和born。節點的屬性能夠隨須要增長或減小,這並不影響結點的使用。
package dbdemo.neo4j.domain; import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.voodoodyne.jackson.jsog.JSOGGenerator; import org.neo4j.ogm.annotation.GraphId; import org.neo4j.ogm.annotation.NodeEntity; @JsonIdentityInfo(generator = JSOGGenerator.class) @NodeEntity public class Actor { @GraphId Long id; private String name; private int born; public Actor() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setBorn(int born) { this.born = born; } public int getBorn() { return born; } }
代碼清單2-22是電影節點實體建模,註解@Realtionship表示List<Role>
是一個關係列表,其中type設定了關係的類型,direction設定這個關係的方向,Relationship.INCOMING表示以這個節點爲終點。addRole定義了增長一個關係的方法。
package dbdemo.neo4j.domain; import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.voodoodyne.jackson.jsog.JSOGGenerator; import org.neo4j.ogm.annotation.GraphId; import org.neo4j.ogm.annotation.NodeEntity; import org.neo4j.ogm.annotation.Relationship; import java.util.ArrayList; import java.util.List; @JsonIdentityInfo(generator = JSOGGenerator.class) @NodeEntity public class Movie { @GraphId Long id; String title; String year; @Relationship(type = "ACTS_IN", direction = Relationship.DIRECTION) List<Role> roles = new ArrayList<>(); public Role addRole(Actor actor, String name) { Role role = new Role(actor, this, name); this.roles.add(role); return role; } public Movie() { } public Long getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } public List<Role> getRoles() { return roles; } }
代碼清單2-23是角色的關係實體建模,註解@RelationshipEntity代表這個類是一個關係實體,並用type指定了關係的類型,其中@StartNode指定起始節點的實體,@EndNode指定終止節點的實體,這說明了圖中一條有向邊的起點和終點的定義。其中定義了一個建立關係的構造函數Role(Actor actor, Movie movie, String name),這裏的name參數用來指定這個關係的屬性。
package dbdemo.neo4j.domain; import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.voodoodyne.jackson.jsog.JSOGGenerator; import org.neo4j.ogm.annotation.EndNode; import org.neo4j.ogm.annotation.GraphId; import org.neo4j.ogm.annotation.RelationshipEntity; import org.neo4j.ogm.annotation.StartNode; @JsonIdentityInfo(generator = JSOGGenerator.class) @RelationshipEntity(type = "ACTS_IN") public class Role { @GraphId Long id; String role; @StartNode Actor actor; @EndNode Movie movie; public Role() { } public Role(Actor actor, Movie movie, String name) { this.actor = actor; this.movie = movie; this.role = name; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public Actor getActor() { return actor; } public Movie getMovie() { return movie; } }
像對其餘數據庫的訪問和存取等操做同樣,spring-data-neo4j提供了功能豐富的資源庫可供調用,所以,對於演員和電影節點實體,能夠建立它們對應的資源庫接口,實現實體的持久化。代碼清單2-24是電影資源庫接口的定義,它繼承於GraphRepository接口,實現了電影實體的持久化。使用相同方法能夠對演員的節點實體實現持久化。關係實體卻不用實現持久化,當保存結點實體時,結點實體的關係將會同時保存。
package dbdemo.neo4j.repositories; import dbdemo.neo4j.domain.Movie; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface MovieRepository extends GraphRepository<Movie> { Movie findByTitle(@Param("title") String title); }
其中GraphRepository接口的繼承關係也遵循了Spring Boot 資源庫定義的規則,即便用與JPA相同的標準規範,因此它一樣包含使用數據庫的豐富功能,如圖2-6所示。
代碼清單2-24是Neo4j的數據庫配置類,其中@EnableTransactionManagement啓用了事務管理,@EnableNeo4jRepositories啓用了Neo4j資源庫並指定了咱們定義的資源庫接口的位置,在重載的SessionFactory函數中設定了定義實體的位置,這將促使定義的實體被做爲域對象導入,RemoteServer設定鏈接Neo4j服務器的URL、用戶名和密碼,這些參數要依據安裝Neo4j服務器的狀況來設置。若是沒有安裝Neo4j服務器,可參考附錄A的方法進行安裝,安裝完成後啓動服務器已備使用。
package dbdemo.neo4j.config; import org.neo4j.ogm.session.SessionFactory; import org.springframework.context.annotation.Configuration; import org.springframework.data.neo4j.config.Neo4jConfiguration; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableTransactionManagement @EnableNeo4jRepositories(basePackages = {"dbdemo.neo4j.repositories"}) public class Neo4jConfig extends Neo4jConfiguration { //SDN 升級到4.1.5,鏈接服務器的配置改在ogm.properties中設定,這樣能夠訪問Neo4j 2.x 到 3.x 版本 // @Override // public Neo4jServer neo4jServer() { // return new RemoteServer("http://192.168.1.221:7474","neo4j","12345678"); // } @Override public SessionFactory getSessionFactory() { return new SessionFactory("dbdemo.neo4j.domain"); } }
如今能夠編寫一個測試程序來驗證和演示上面編寫的代碼的功能,如代碼清單2-26所示。這個測試程序分別建立了三部電影和三個演員,以及三個演員在三部電影中各自扮演的角色,而後按照電影標題查出一部電影,按照其內在的關係輸出這部電影的信息和每一個演員扮演的角色。這些數據的內容參照了Neo4j幫助文檔中提供的示例數據。
package dbdemo.neo4j.test; import dbdemo.neo4j.config.Neo4jConfig; import dbdemo.neo4j.domain.Actor; import dbdemo.neo4j.domain.Movie; import dbdemo.neo4j.domain.Role; import dbdemo.neo4j.repositories.ActorRepository; import dbdemo.neo4j.repositories.MovieRepository; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Assert; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {Neo4jConfig.class}) public class MovieTest { private static Logger logger = LoggerFactory.getLogger(MovieTest.class); @Autowired MovieRepository movieRepository; @Autowired ActorRepository actorRepository; @Before public void initData() { movieRepository.deleteAll(); actorRepository.deleteAll(); Movie matrix1 = new Movie(); matrix1.setTitle("The Matrix"); matrix1.setYear("1999-03-31"); Movie matrix2 = new Movie(); matrix2.setTitle("The Matrix Reloaded"); matrix2.setYear("2003-05-07"); Movie matrix3 = new Movie(); matrix3.setTitle("The Matrix Revolutions"); matrix3.setYear("2003-10-27"); Actor keanu = new Actor(); keanu.setName("Keanu Reeves"); Actor laurence = new Actor(); laurence.setName("Laurence Fishburne"); Actor carrieanne = new Actor(); carrieanne.setName("Carrie-Anne Moss"); matrix1.addRole(keanu, "Neo"); matrix1.addRole(laurence, "Morpheus"); matrix1.addRole(carrieanne, "Trinity"); movieRepository.save(matrix1); Assert.notNull(matrix1.getId()); matrix2.addRole(keanu, "Neo"); matrix2.addRole(laurence, "Morpheus"); matrix2.addRole(carrieanne, "Trinity"); movieRepository.save(matrix2); Assert.notNull(matrix2.getId()); matrix3.addRole(keanu, "Neo"); matrix3.addRole(laurence, "Morpheus"); matrix3.addRole(carrieanne, "Trinity"); movieRepository.save(matrix3); Assert.notNull(matrix3.getId()); } @Test public void get() { Movie movie = movieRepository.findByTitle("The Matrix"); Assert.notNull(movie); logger.info("===movie=== movie:{}, {}", movie.getTitle(), movie.getYear()); for (Role role : movie.getRoles()) { logger.info("====== actor:{}, role:{}", role.getActor().getName(), role.getRole()); } } }
在IDEA的Run/Debug Configuration配置中增長一個JUnit的配置項目,模塊選擇neo4j,工做目錄選擇模塊所在的根目錄,測試程序選擇MovieTest這個類,並將配置保存爲neo4jtest。
使用Debug模式運行測試項目neo4jtest,若是測試經過,將在控制檯中看到輸出查詢的這部電影和全部演員及其扮演的角色,以下所示:
=== movie === movie:The Matrix, 1999-03-31 ===== actor:keanu Reeves, role:Neo ===== actor:Laurence Fishburne, role:Morpheus ===== actor:Carrie-Anne Moss, role:Trinty
這時,在數據庫客戶端的控制檯上,單擊左側欄的關係類型ACTS_IN,能夠看到一個很酷的圖形,圖中每部電影和每一個演員是一個節點,節點的每條有向邊表明了這個演員在那部電影中扮演的角色,如圖2-7所示。
這一章,咱們一口氣學習使用了4種數據庫:MySQL、Redis、MonogoDB、Neo4j,除了Redis之外,都使用了由Spring Boot提供的資源庫來訪問數據庫並對數據庫執行了通常的存取操做。能夠看出,在Spring Boot框架中使用數據庫很是簡單、容易,這主要得益於Spring Boot資源庫的強大功能,Spring Boot資源庫整合了第三方資源,它把複雜的操做變成簡單的調用,它把全部「辛苦、繁重的事情」都包攬了,而後將「微笑和鮮花」獻給了咱們。爲此,咱們應該說聲謝謝,謝謝開發Spring Boot框架及全部第三方提供者的程序員們,由於有了他們辛勤的付出,纔有了咱們今天使用上的便利。
本章實例的完整代碼能夠在IDEA中直接從GitHub中檢出。
本章實例都是使用JUnit的方式來驗證的,爲了能使用友好的界面來運行應用,下一章將介紹如何使用Thymeleaf來進行界面設計。