此文省略Springboot项目的创建以及初始化
学习书籍《深入实践SpringBoot》
1、MySQL
对于传统关系型数据库(如MySQL)来说,SpringBoot使用JPA(Java Persistence API)资源库实现对数据库的操作。JPA是为POJO(Plain Ordinary Java Object)提供持久化的标准规范。
1.1、配置依赖
通过项目模块配置文件pom.xml进行引入JPA和MySQL的依赖
<!-- ... --><dependencies><!-- mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.21</version></dependency><!-- jpa--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency></dependencies><!-- ... -->
1.2、实体配置
实体-关系模型示例
下面对以上三个实体进行建模:
部门Deparment:
packagedbdemo.mysql.entity;importjavax.persistence.*;@Entity@Table(name="department")publicclassDepartment{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLong id;privateString name;publicDepartment(){}/**
*省略 setter 以及getter方法。
*/}
用户User:
packagedbdemo.mysql.entity;importcom.fasterxml.jackson.annotation.JsonBackReference;importcom.fasterxml.jackson.annotation.JsonIgnore;importorg.springframework.format.annotation.DateTimeFormat;importjavax.persistence.*;importjava.util.Date;importjava.util.List;@Entity@Table(name="user")publicclassUserimplementsjava.io.Serializable{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLong id;privateString name;@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")privateDate createdate;@ManyToOne@JoinColumn(name="did")@JsonBackReferenceprivateDepartment deparment;@ManyToMany(cascade={}, fetch=FetchType.EAGER)@JoinTable(name="user_role",
joinColumns={@JoinColumn(name="user_id")},
inverseJoinColumns={@JoinColumn(name="roles_id")})privateList<Role> roles;publicUser(){}/**
*省略 setter 以及getter方法。
*/}
角色Role:
packagedbdemo.mysql.entity;importjavax.persistence.*;@Entity@Table(name="role")publicclassRoleimplementsjava.io.Serializable{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLong id;privateString name;publicRole(){}/**
*省略 setter 以及getter方法。
*/}
通过以上三个实体定义,实现了使用Java普通对象(POJO)与数据库表建立映射关系(ORM)。
1.3、JPA实现持久化
JPA是一个接口,继承JPA资源库JpaRepository接口,使用注解@Repository将该接口定义为一个资源库,为其他程序提供存取数据库的功能。
分别对三个实体使用JPA存取数据库实现持久化
packagedbdemo.mysql.repository;importdbdemo.mysql.entity.Department;importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.stereotype.Repository;@RepositorypublicinterfaceDepartmentRepositoryextendsJpaRepository<Department,Long>{}
packagedbdemo.mysql.repository;importdbdemo.mysql.entity.Role;importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.stereotype.Repository;@RepositorypublicinterfaceRoleRepositoryextendsJpaRepository<Role,Long>{}
packagedbdemo.mysql.repository;importdbdemo.mysql.entity.User;importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.stereotype.Repository;importjava.util.Date;importjava.util.List;@RepositorypublicinterfaceUserRepositoryextendsJpaRepository<User,Long>{UserfindByNameLike(String name);UserreadByName(String name);List<User>getByCreatedateLessThan(Date star);}
1.4、测试
测试之前,需要保证Mysql中存在你想要访问的数据库,这里假设访问的数据库为test,而用户名设为 root ,密码为 admin。test数据库中是否存在对应的表table并不重要,因为Springboot运行后会帮你创建对应的表结构。
接下来进行实例测试来证明以上设计的正确性:
- 首先配置JPA配置类:JpaConfiguration.class
packagedbdemo.mysql.config;importorg.springframework.boot.orm.jpa.EntityScan;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.Ordered;importorg.springframework.core.annotation.Order;importorg.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;importorg.springframework.data.jpa.repository.config.EnableJpaRepositories;importorg.springframework.transaction.annotation.EnableTransactionManagement;@Order(Ordered.HIGHEST_PRECEDENCE)@Configuration@EnableTransactionManagement(proxyTargetClass=true)@EnableJpaRepositories(basePackages="dbdemo.**.repository")@EntityScan(basePackages="dbdemo.**.entity")publicclassJpaConfiguration{@BeanPersistenceExceptionTranslationPostProcessorpersistenceExceptionTranslationPostProcessor(){returnnewPersistenceExceptionTranslationPostProcessor();}}
各注解含义:
- EnableTransactionManagement :启动JPA的事务管理
- EnableJpaRepositories:启用JPA资源库并指定上面定义的接口资源库的位置;
- EntityScan:指定了定义实体的所在位置,对我们所定义的实体进行导入
而在测试中使用的JPA配置类并不是像以上的配置这样简便,我们需要把一些配置参数都包含在用于测试的配置类类定义中,配置内容如下:
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.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("admin");
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());
}
}
- 在Springboot的配置文件application.yml中天界配置来设置数据源和JPA的工作模式:
spring:datasource:url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8username: rootpassword: adminjpa:database: MYSQLshow-sql:truehibernate:ddl-auto: updatenaming-strategy: org.hibernate.cfg.ImprovedNamingStrategyproperties:hibernate:dialect: org.hibernate.dialect.MySQL5Dialect
另外如果是利用application.properties文件进行配置的话,如下:
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
jpa.database=MYSQL
jpa.show-sql=true
jpa.hibernate.ddl-auto=update
jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
jpa.properties.hibernate=
jpa.properties.dialect=org.hibernate.dialect.MySQL5Dialect
- 接下来编写MysqlTest测试类
- 还有一件事 :
测试用的程序都需要置于项目目录下的src/test/java目录下,否则不能正常进行测试
packagedbdemo.mysql.test;importdbdemo.mysql.entity.Department;importdbdemo.mysql.entity.Role;importdbdemo.mysql.entity.User;importdbdemo.mysql.repository.DepartmentRepository;importdbdemo.mysql.repository.RoleRepository;importdbdemo.mysql.repository.UserRepository;importorg.junit.Before;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.PageRequest;importorg.springframework.data.domain.Pageable;importorg.springframework.data.domain.Sort;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;importorg.springframework.util.Assert;importjava.util.*;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={JpaConfiguration.class})publicclassMysqlTest{privatestaticLogger logger=LoggerFactory.getLogger(MysqlTest.class);@AutowiredUserRepository userRepository;@AutowiredDepartmentRepository departmentRepository;@AutowiredRoleRepository roleRepository;@BeforepublicvoidinitData(){
userRepository.deleteAll();
roleRepository.deleteAll();
departmentRepository.deleteAll();Department department=newDepartment();
department.setName("开发部");
departmentRepository.save(department);Assert.notNull(department.getId());Role role=newRole();
role.setName("admin");
roleRepository.save(role);Assert.notNull(role.getId());User user=newUser();
user.setName("user");
user.setCreatedate(newDate());
user.setDeparment(department);List<Role> roles= roleRepository.findAll();Assert.notNull(roles);
user.setRoles(roles);
userRepository.save(user);Assert.notNull(user.getId());}@TestpublicvoidfindPage(){Pageable pageable=newPageRequest(0,10,newSort(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());}}//@Testpublicvoidtest(){User user1= userRepository.findByNameLike("u%");Assert.notNull(user1);User user2= userRepository.readByName("user");Assert.notNull(user2);List<User> users= userRepository.getByCreatedateLessThan(newDate());Assert.notNull(users);}}
2、Redis
Redis是一种可以持久存储的缓存系统,是高性能的key-value数据库,Redis中的数据主要都存储在内存之中,只有部分存在硬盘之中,它通过json数据实现key-value数据的存储。
Redis官网下载
2.1、配置依赖
SpringBoot中使用Redis,也需要在工程中的Maven配置文件pom.xml中加入spring-boot-starter-redis依赖。
pom.xml中Redis模块的Maven依赖配置:
<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>
2.2、Redis服务类
Redis提供的数据类型如下:
- string
- hash
- list
- set 以及 zset
实例使用string字符串类型演示数据的存取操作。
Springboot并没有提供如JPA那样的资源库接口,需要根据Repository的定义写个User的服务类。
packagedbdemo.redis.repository;importcom.google.gson.Gson;importcom.google.gson.reflect.TypeToken;importdbdemo.mysql.entity.User;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.stereotype.Repository;importorg.springframework.util.StringUtils;importjava.util.List;importjava.util.concurrent.TimeUnit;@RepositorypublicclassUserRedis{<