SpringBoot 学习笔记2
使用数据库
SpringBoot使用JPA(Java Persistence API)资源库实现对数据库的操作。
JPA为POJO(Plain Ordinary Java Object)提供持久化的标准规范。将Java对象通过关系映射(ORM)持久化到数据库中。
在工程中引入JPA和MySQL的Maven依赖。
<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>
实体建模
部门实体,含有两个字段id和name。
其中的get和set方法可由idea自动生成。
@Table 指定关联数据库的表名
@Id 定义一条记录的唯一标识
@GeneratedValue 将其设置为自动生成。
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
@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唯一且自动生成
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;
}
}
以上三个实体的定义实现了普通对象POJO与数据表的映射关系ORM
使用JPA持久化
UserRespository继承于JPA的JpaRepository接口
@Repository 将其定义为一个资源库,能被其他程序引用并提供存取数据库功能
注意使用的参数是各自的实体对象
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> getByCreatedateLessThan(Date star);
}
JPA提供了自定义声明方法的规则,使用fingBy,getBy等作为前缀,与实体中的属性字段拼接,还可选拼接一些查询关键字即可组成一个查询方法。
这些方法不用实现,JPA会代理将其实现。
使用JPA的配置类
@EnableTransactionManagement 启用了JPA的事务管理
@EnableJpaRepositories 启用了JPA资源库并指定了上面接口资源库的位置
@EntityScan指定了定义实体的位置
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();
}
}
这个配置的参数是从配置文件中读取的,实际测试时的配置类把配置参数包含在类定义中
设置数据源和JPA的工作模式
创建数据库test,数据库的表结构会在运行时自动创建。同时授予本地测试用户root完全访问权限。
application.yml
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自动更新表结构,在数据表不存在时则创建,修改表结构时则在程序启动后同步更新。
MySQL测试实例
MysqlTest.java
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
public void test(){
User user1 = userRepository.findByNameLike("u%");
Assert.notNull(user1);
User user2 = userRepository.readByName("user");
Assert.notNull(user2);
List<User> users = userRepository.getByCreatedateLessThan(new Date());
Assert.notNull(users);
}
}
使用JUint测试,运行配置如下