Spring Boot 最佳实践(五)Spring Data JPA 操作 MySQL 8

43次阅读

共计 6073 个字符,预计需要花费 16 分钟才能阅读完成。

一、Spring Data JPA 介绍
JPA(Java Persistence API)Java 持久化 API,是 Java 持久化的标准规范,Hibernate 是持久化规范的技术实现,而 Spring Data JPA 是在 Hibernate 基础上封装的一款框架。
开发环境

Spring Boot 2.0.4
Spring Data JPA 2.0.4
MySQL 8.0.12
JDK 8
IDEA 2018.2
Windows 10

<!–more–>
二、集成步骤
2.1 配置依赖
添加 Spring Data JPA 和 MySQL Connector,配置 pom.xml 文件,代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
更多 JPA 版本:http://mvnrepository.com/arti…
更多 Mysql 版本:http://mvnrepository.com/arti…
2.2 application.properties 设置配置文件
## 数据源配置
spring.datasource.url=jdbc:mysql://172.16.10.79:3306/mytestdb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true

hbm2ddl.auto:自动创建 | 更新 | 验证数据库表结构
dialect:设置数据库引擎为 InnoDB
show-sql:打印 sql 语句,方便调试

hbm2ddl.auto 有四个属性:

create:每次加载 hibernate 时都会删除上一次的生成的表,然后根据你的 model 类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。[删除 - 创建 - 操作]
create-drop:每次加载 hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。[删除 - 创建 - 操作 - 再删除]
update:最常用的属性,第一次加载 hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载 hibernate 时根据 model 类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。[没表 - 创建 - 操作 | 有表 - 更新没有的属性列 - 操作]
validate:每次加载 hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。[启动验证表结构,验证不成功,项目启动失败]

2.3 增加实体类(Entity)
@Entity
public class User implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(name = “name”, nullable = false)
private String name;
@Column(nullable = false)
private int age;
@Column(nullable = false)
private String pwd;
public User(){}
public User(String name, int age, String pwd) {
this.name = name;
this.age = age;
this.pwd = pwd;
}
//… 忽略 set、get 方法
}

@GeneratedValue 自动生成 id
@Column 设置列属性(name=” 数据库列名 ”)
@Transient 不会映射到数据库

2.4 创建 Repository 接口构建业务方法
public interface UserRepository extends JpaRepository<User,Long> {
public User findByName(String name);
}
继承 JpaRepository 之后就继承了:

Repository.save(user); // 插入或保存
Repository.saveFlush(user); // 保存并刷新
Repository.exists(1) // 主键查询是否存在
Repository.findOne(1); // 主键查询单条
Repository.delete(1); // 主键删除
Repository.findByUsername(“stone”); // 查询单条
Repository.findAll(pageable); // 带排序和分页的查询列表
Repository.saveState(1, 0); // 更新单个字段

这些方法,可以不写一行代码就可以实现对一个表的操作,当然你也可以扩展一些自己的方法,只需要在 UserRepository 里面添加方法即可。
2.5 添加、查询数据库
@Controller
@RequestMapping(“/”)
public class UserController {

@Autowired
private UserRepository userRepository;

@RequestMapping(“/”)
public ModelAndView index() {
userRepository.save(new User(“ 老王 ”,18,”123456″));
ModelAndView modelAndView = new ModelAndView(“/index”);
modelAndView.addObject(“dataSize”, userRepository.findAll().size());
return modelAndView;
}
}
到现在为止,集成 Spring Data JPA 已经全部完成了,启动调试,查看运行效果吧。
三、高级使用
本节高级使用将会涉及的知识点如下:

事务实现
根据名称自动生成 SQL
自定义 Sql 语句查询

3.1 事务实现
3.1.1 Spring 事务实现步骤
实现事务,只需要两步即可:
步骤一、在 application.properties 配置数据库引擎为 InnoDB:
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
步骤二、在方法或类上标识事务 @Transactional
示例代码:
@Transactional
public void saveGroup(){
userRepository.save(user);
userRepository.save(user2);
}
如果出现错误,就会进行事务回滚。
3.1.2 事务不生效的原因
3.1.2.1 确认数据库引擎
在 application.properties 配置数据库引擎为 InnoDB:
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
3.1.2.2 查看表的引擎必须为 InnoDB
通过命令:
show table status from mytestdb;

修改表的引擎:
alter table table_name engine=innodb;
3.1.2.3 注意引入 @Transactional 的命名空间
@Transactional 注解来自 org.springframework.transaction.annotation 包,而不是 javax.transaction.
3.2 根据名称自动生成 SQL
JPA 支持根据简单的关键字自动生成 Sql 查询的方法,比如根据 name 和 age 的组合查询,代码如下:
public User findByNameAndAge(String name,int age);
使用关键字“And”即可,或者查询时间区间的:
public User findByStartDateBetween(Long startDate);
使用关键字“Between”即可。
更多内部支持的关键字,如下表:

Keyword
Sample
JPQL snippet

And
findByLastnameAndFirstname
… where x.lastname = ?1 and x.firstname = ?2

Or
findByLastnameOrFirstname
… where x.lastname = ?1 or x.firstname = ?2

Is,Equals
findByFirstname,findByFirstnameIs
… where x.firstname = ?1

Between
findByStartDateBetween
… where x.startDate between ?1 and ?2

LessThan
findByAgeLessThan
… where x.age < ?1

LessThanEqual
findByAgeLessThanEqual
… where x.age <= ?1

GreaterThan
findByAgeGreaterThan
… where x.age > ?1

GreaterThanEqual
findByAgeGreaterThanEqual
… where x.age >= ?1

After
findByStartDateAfter
… where x.startDate > ?1

Before
findByStartDateBefore
… where x.startDate < ?1

IsNull
findByAgeIsNull
… where x.age is null

IsNotNull,NotNull
findByAge(Is)NotNull
… where x.age not null

Like
findByFirstnameLike
… where x.firstname like ?1

NotLike
findByFirstnameNotLike
… where x.firstname not like ?1

StartingWith
findByFirstnameStartingWith
… where x.firstname like ?1(parameter bound with appended %)

EndingWith
findByFirstnameEndingWith
… where x.firstname like ?1(parameter bound with prepended %)

Containing
findByFirstnameContaining
… where x.firstname like ?1(parameter bound wrapped in %)

OrderBy
findByAgeOrderByLastnameDesc
… where x.age = ?1 order by x.lastname desc

Not
findByLastnameNot
… where x.lastname <> ?1

In
findByAgeIn(Collection<Age> ages)
… where x.age in ?1

NotIn
findByAgeNotIn(Collection<Age> ages)
… where x.age not in ?1

True
findByActiveTrue()
… where x.active = true

False
findByActiveFalse()
… where x.active = false

IgnoreCase
findByFirstnameIgnoreCase
… where UPPER(x.firstame) = UPPER(?1)

官方文档:https://docs.spring.io/spring…
3.3 自定义 Sql 语句查询
对于用户自己编写 sql,Spring Boot JPA 也有很好的支持,只需要添加 @Query(sql) 即可。
示例代码:
@Transactional
@Modifying
@Query(“update User set name=?1 where id=?2″)
public int modifyName(String name,Long id);
注意:在执行修改和删除的时候必须添加 @Modifying 注解,ORM 才知道要执行写操作,update/delete query 的时候,也必须需要加上 @Transactional(事务)才能正常操作。
四、常见错误
在 Spring Data JPA 的使用当中,可能会遇到如下的一些错误。
1.No default constructor for entity
实体类 Entity 没有空参数的默认构造函数,新增即可解决。
2.java.sql.SQLException: Access denied for user ”@’172.17.0.1′ (using password: NO)
启动项目报错,用户名和密码配置的 key 有误,MySQL8 的用户名和密码配置和之前的不一样,MySQL 8 正确的用户名密码配置如下:
spring.datasource.username=root
spring.datasource.password=123456
# 以下为配置老数据库驱动配置
#spring.datasource.data-username=root
#spring.datasource.data-password=123456
3.Caused by: java.lang.IllegalStateException: Cannot load driver class: com.mysql.jdbc.Driver
MySQL 8 的 spring.datasource.driver-class-name 配置需要改为“com.mysql.cj.jdbc.Driver”而不是“com.mysql.jdbc.Driver”,正确配置如下:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

正文完
 0