spring boot 2.1学习笔记【六】SpringBoot 2集成MySQL,Spring Data JPA
springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich。
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。springboot系列代码全部上传至GitHub:https://github.com/liubenlong/springboot2_demo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;
文章目录
使用spring data jpa
使用JpaRepository默认方法
使用自定义的方法
使用@Query来指定本地查询
事物
多数据源事务
遇到的异常
time zone 时区错误
mysql-connector-java 8.X 版本的驱动的SSL问题
配置项说明
使用spring data jpa
需要添加以下依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
最简化的配置(为了打印SQL这里配置了show-sql):
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/test
username: ***
password: ***
jpa:
show-sql: true
创建测试的数据库
CREATE TABLE `stu` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`address` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
随便添加一条记录。
编写Stu的实体类:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.io.Serializable;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Stu implements Serializable {
@Id
/*
这里是hibernate的主键生成策略。oracle中需要 设置sequence,MySQL中则指定identity使用自增字段。具体请参考hibernate的配置
*/
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column
private Integer age;
@Column
private String address;
}
编写dao层。JpaRepository是springdata提供的的数据库访问层的工具类,可以大大简化代码的编写。JpaRepository提供了以下方法,可以满足大部分的需求:
import com.example.pojo.Stu; import org.springframework.data.jpa.repository.JpaRepository; public interface StuRepository extends JpaRepository<Stu, Long> { }
使用JpaRepository默认方法
为了简单,我没有写service;
import com.example.dao.StuRepository; import com.example.pojo.Stu; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.*; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Arrays; import java.util.List; @RestController @Slf4j public class StuController { @Autowired private StuRepository stuRepository; @GetMapping("/findAll") public List<Stu> findAll() { List<Stu> stus = stuRepository.findAll(); return stus; } /** * 创建 * * @return */ @GetMapping("/createOne") public List<Stu> createOne() { Stu stu = Stu.builder().name("李四").age(12).address("西湖").build(); Stu save = stuRepository.save(stu); log.info(save.toString()); List<Stu> stus = Arrays.asList(Stu.builder().name("李四").age(12).address("西湖").build(), Stu.builder().name("王五").age(12).address("南京路").build(), Stu.builder().name("交易员韩国").age(12).address("二环").build()); List<Stu> stus1 = stuRepository.saveAll(stus); return stus1; } @GetMapping("/deleteById") public void deleteById() { stuRepository.existsById(1L);//判断是否存在 stuRepository.deleteById(1L);//删除 } /** * 根据条件查询 * * @return */ @GetMapping("/findByExample") public List<Stu> findByExample() { Stu stu = Stu.builder().age(12).build(); Example<Stu> example = Example.of(stu); List<Stu> all = stuRepository.findAll(example); return all; } /** * 实现分页查询 * * @return */ @GetMapping("/findWithPage") public Page<Stu> findWithPage() { Stu stu = Stu.builder().age(12).build(); Example<Stu> example = Example.of(stu); Page<Stu> all = stuRepository.findAll(example, PageRequest.of(1, 5, Sort.by("name"))); return all; } }
启动服务, 可以看到默认是使用Hibernate:
另外需要说明的是,1.5.X版本springboot连接池默认是使用的Tomcat连接池,2.X版本默认使用hikari连接池。具体参见另一篇文章springboot 中数据源配置,连接池配置,源码剖析,如何选择连接池。hikari连接池后续再讲
接口访问结果:
更加详细的JpaRepository用法请自行搜索。
使用自定义的方法
自定义的简单查询就是根据方法名来自动生成SQL,主要的语法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称。
按照Spring Data的规范,查询方法以find | read | get 开头,涉及查询条件时,条件的属性用条件关键字连接,
要注意的是:条件属性以首字母大写。
实例:我们在StuRepository中添加一个方法:
public interface StuRepository extends JpaRepository<Stu, Long> { /** * 根据名字自定义方法 * @param name * @param age * @return */ List<Stu> findByNameAndAge(String name, int age); }
编写测试方法:
/** * 使用自定义的查询方法 * 其实上面的JpaRepository默认的方法已经够用了,这个可不使用。经常用到的方法可以写,减少代码量 * @return */ @GetMapping("/findByNameAndAge") public List<Stu> findByNameAndAge() { List<Stu> stus = stuRepository.findByNameAndAge("李四", 12); return stus; }
使用@Query来指定本地查询
有时候可能需要自己编写SQL,那么可以使用@Query来编写自己的SQL语句
实例:
public interface StuRepository extends JpaRepository<Stu, Long> { @Query(value="select * from stu where name like %?%" ,nativeQuery=true) List<Stu> findLikeName(String name); }
暂不支持翻页及动态排序等功能。除非使用JpaRepository不能满足需求,否则一般不会自己来编写SQL。
事物
spring提供了声明式的事务管理@Transactional。使用起来非常方便。这里只展示如何使用,具体原理后续再讲。
由于spring的事务管理是通过AOP动态代理实现的,所以调用方与事务方法不得在同一个方法内。
这里我们新建一个StuServer:
@Component @Slf4j public class StuService { @Autowired private StuRepository stuRepository; @Transactional(rollbackFor = Exception.class) public void createStu() { Stu stu = Stu.builder().age(100).address("1111").name("周星星").build(); Stu save = stuRepository.save(stu); log.info(save.toString()); int a = 1/0; stu = Stu.builder().age(200).address("2222").name("周星星2").build(); Stu save1 = stuRepository.save(stu); log.info(save1.toString()); } }
在controller中测试
/** *事务测试 * @return */ @GetMapping("/testTransactional") public void testTransactional() { stuService.createStu(); }
注意:这里rollbackFor最好写上,否则可能会存在一些运行时异常不活不到哦。
多数据源事务
请参考笔者另一篇文章: spring boot多数据源配置,多数据源事务。只需要注意每个事务方法都明确指定事务管理器就行了(如果不加事务管理器,默认是第一个加载的数据源的事务)。
遇到的异常
time zone 时区错误
The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the
server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize
time zone support.
1
2
3
解决办法:
使用root用户登录mysql,执行命令show variables like '%time_zone%';
发现时区是系统默认的,而默认是美国时区,而我们中国要比他们迟8小时。所以需要对其进行修改:
set global time_zone='+8:00';
执行完成之后,再次查询
如果没有变为+8:00,退出客户端,重新登录查询即可。
另外一种解决办法在连接URL上指定serverTimezone):
jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
mysql-connector-java 8.X 版本的驱动的SSL问题
我们这里手动禁用ssl,否则会报错javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify
如何使用SSL后续再测试。
参考:http://www.360doc.com/content/18/0725/10/15874231_773062498.shtml
配置项说明
# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) spring.datasource.continue-on-error=false # Whether to stop if an error occurs while initializing the database. spring.datasource.data= # Data (DML) script resource references. spring.datasource.data-username= # Username of the database to execute DML scripts (if different). spring.datasource.data-password= # Password of the database to execute DML scripts (if different). spring.datasource.dbcp2.*= # Commons DBCP2 specific settings spring.datasource.driver-class-name= # Fully qualified name of the JDBC driver. Auto-detected based on the URL by default. spring.datasource.generate-unique-name=false # Whether to generate a random datasource name. spring.datasource.hikari.*= # Hikari specific settings spring.datasource.initialization-mode=embedded # Initialize the datasource with available DDL and DML scripts. spring.datasource.jmx-enabled=false # Whether to enable JMX support (if provided by the underlying pool). spring.datasource.jndi-name= # JNDI location of the datasource. Class, url, username & password are ignored when set. spring.datasource.name= # Name of the datasource. Default to "testdb" when using an embedded database. spring.datasource.password= # Login password of the database. spring.datasource.platform=all # Platform to use in the DDL or DML scripts (such as schema-${platform}.sql or data-${platform}.sql). spring.datasource.schema= # Schema (DDL) script resource references. spring.datasource.schema-username= # Username of the database to execute DDL scripts (if different). spring.datasource.schema-password= # Password of the database to execute DDL scripts (if different). spring.datasource.separator=; # Statement separator in SQL initialization scripts. spring.datasource.sql-script-encoding= # SQL scripts encoding. spring.datasource.tomcat.*= # Tomcat datasource specific settings spring.datasource.type= # Fully qualified name of the connection pool implementation to use. By default, it is auto-detected from the classpath. spring.datasource.url= # JDBC URL of the database. spring.datasource.username= # Login username of the database. spring.datasource.xa.data-source-class-name= # XA datasource fully qualified name. spring.datasource.xa.properties= # Properties to pass to the XA data source. # JPA (JpaBaseConfiguration, HibernateJpaAutoConfiguration) spring.data.jpa.repositories.bootstrap-mode=default # Bootstrap mode for JPA repositories. spring.data.jpa.repositories.enabled=true # Whether to enable JPA repositories. spring.jpa.database= # Target database to operate on, auto-detected by default. Can be alternatively set using the "databasePlatform" property. spring.jpa.database-platform= # Name of the target database to operate on, auto-detected by default. Can be alternatively set using the "Database" enum. spring.jpa.generate-ddl=false # Whether to initialize the schema on startup. spring.jpa.hibernate.ddl-auto= # DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property. Defaults to "create-drop" when using an embedded database and no schema manager was detected. Otherwise, defaults to "none". spring.jpa.hibernate.naming.implicit-strategy= # Fully qualified name of the implicit naming strategy. spring.jpa.hibernate.naming.physical-strategy= # Fully qualified name of the physical naming strategy. spring.jpa.hibernate.use-new-id-generator-mappings= # Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. spring.jpa.mapping-resources= # Mapping resources (equivalent to "mapping-file" entries in persistence.xml). spring.jpa.open-in-view=true # Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request. spring.jpa.properties.*= # Additional native properties to set on the JPA provider. spring.jpa.show-sql=false # Whether to enable logging of SQL statements.
springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich。
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。springboot系列代码全部上传至GitHub:https://github.com/liubenlong/springboot2_demo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;