springBoot 集成Mysql数据库
springBoot 集成Mysql数据库
前一段时间,我们大体介绍过SpringBoot,想必大家还有依稀的印象。我们先来回顾一下:SpringBoot是目前java世界最流行的一个企业级解决方案框架。它深度绑定了依赖注入和面向切片两种编程思想。并且通过自动化的方式减少了编程人员在开发过程中大量的繁琐的配置和通用的配置型的编码,让编程人员可以更加聚焦于业务,解决实际的问题。
我们的日常工作有机会主要是围绕数据库进行编程和设计,那么数据库的增删改查对于我们来说可以说是最重要最核心最需要掌握的能力。
本次,我们假设大家已经按照上次培训的内容,下载了对应的spring框架,开发编译器,maven等必备工具。在此基础上,我们来聊聊springBoot集成Mysql数据库。希望通过学习后,大家能够发挥聪明材质,将Mysql库更换成oracle库甚至是sqlserver库。
mysql库的安装,网络上有很多其他教程,在此略过不谈,我们假设大家的mysql库已经安装完毕。直接开始mysql库的集成工作。
springBoot链接数据库,有三种方式:
- 采用JDBC直接链接
- 采用JdbcTemplate链接
- 采用SpringDataJPA链接
- 通过其他框架链接
JDBC直接链接繁琐,易错。我们直接略过,不做考虑。通过其他框架如MyBatis等,种类繁多,我们后续再讲。本次我们重点讲解JdbcTemplate和SpringDataJPA。特别是SpringDataJPA。
JdbcTemplate在JDBC的基础上做了大量的封装,SpringDataJPA是基于JPA(java持久化规范,本质上是ORM)的规范的一层封装,JPA的具体的实现有Hibernate,OpenJPA等。JdbcTemplate和SpringDataJPA的最大区别是JdbcTemplate主要操作sql数据库,SpringDataJPA主要操作对象。
我们首先了解采用JdbcTemplate链接mysql
首先第一步,修改maven的pom文件,将mysql和jdbc依赖添加进去。
//第一个dependency,是添加的mysql链接java的驱动程序
//第二个dependency,是支持通过JDBC链接数据库。和C#的ADO一样,都是基于ODBC链接的。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
第二步,在配置文件application.properties中添加mysql链接串
###mysql 连接信息,test是数据库名
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
###用户名
spring.datasource.username=root
###密码
spring.datasource.password=sa
###驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
第三步,设计数据库表
CREATE TABLE `ay_user` (
`id` varchar(32) NOT NULL,
`name` varchar(10) DEFAULT NULL COMMENT '用户名',
`password` varchar(32) DEFAULT NULL COMMENT '密码'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
第四步,建立对应的数据库实体
public class AyUser {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private String id;
private String name;
private String password;
}
第五步利用springboot的jdbc类读取。此处采用一个测试用例展现
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void mySqlTest(){
String sql = "select id,name,password from ay_user ";
//query(),查询方法,传入sql语句和RowMapper对象,返回对象List。
//RowMapper对象,将查询出来的每一行数据封装成用户定义的类
List<AyUser> userList = (List<AyUser>) jdbcTemplate.query(sql, new RowMapper<AyUser>() {
@Override
public AyUser mapRow(ResultSet re, int rowNum) throws SQLException {
AyUser user = new AyUser();
user.setId(re.getString("id"));
user.setName(re.getString("name"));
user.setPassword(re.getString("password"));
return user;
}
});
System.out.println("查询成功:");
for (AyUser user:userList){
System.out.println("[id]:"+user.getId()+";[name]:"+user.getName());
}
}
此处有部分细节需要进一步阐释。
@Resource
private JdbcTemplate jdbcTemplate;
JdbcTemplate是一个通过JDBC链接数据库的工具类,maven的pom文件中引入的
spring-boot-starter-data-jdbc中包含了spring-jdbc的包,我们主要通过它
来完成增删改查
@Resource代表自动注入,通过这个注解,项目启动后,SpringBoot会帮助我们实例化一个
JdbcTemplate对象,省去初始化工作
对于各种注解,可以查看一个脑图,这个脑图是基于自己的理解自行整理的,可能有错误或不全面,后面可以可以共同优化。
那么采用SpringDataJPA如何操作mysql数据库呢?
具体操作之前,我们简单了解一下SpringDataJPA。
SpringDataJPA最顶层的接口是Repository,它是一个空的,只定义了泛型和ID关键字(可以查看Repository源码),CrudRepository则提供了基本的增删改查接口,PagingAndSortingRepository提供了基本的分页和排序接口,JpaRepository继承了上述接口,是我们常用的底层的接口。
具体如何使用呢?
第一步,修改maven的pom文件,将jpa依赖添加进去。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
第二步,创建一个接口继承JpaRepository接口(后期可以添加一些自定义的东西)
public interface AyUserRepository extends JpaRepository<AyUser,String> {
//自定义内容
List<AyUser> findByName(String name);
List<AyUser> findByNameLike(String name);
List<AyUser> findByIdIn(Collection<String> ids);
}
SpringDataJPA约定了一系列规范,JPA会根据代码翻译成相关的sql。如findBy,Like,In等关键字。
可从官网https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories的5.3.2的table3中查看全部写法。
不完整截图如下:
第三步,修改AyUser类,添加@Entity, @Id注解。
@Entity//每个持久化POJO类都是一个实体Bean,通过此注解申明
@Table(name="ay_user")//对象映射到数据库的表,如果没有,Spring会根据class的名字进行寻找
public class AyUser {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Id//表示表的主键
private String id;
private String name;
private String password;
}
第四部,模拟一个简单的JPA实现
public interface AyUserService {
AyUser findById(String id);
List<AyUser> findAll();
AyUser save(AyUser ayUser);
void delete(String id);
//Pageable是一个分页接口,Page是一个分页查询结果借口
Page<AyUser> findAll(Pageable pageable);
List<AyUser> findByName(String name);
List<AyUser> findByNameLike(String name);
List<AyUser> findByIdIn(Collection<String> ids);
}
@Service//服务类注解,和@Component起到类似的作用:自动扫描并注册到Spring容器中
public class AyUserServiceImpl implements AyUserService {
@Resource//自动扫描AyUserRepository并注册
private AyUserRepository ayUserRepository;
@Override
public AyUser findById(String id) {
return ayUserRepository.findById(id).get();
}
@Override
public List<AyUser> findAll() {
return ayUserRepository.findAll();
}
@Override
public AyUser save(AyUser ayUser) {
return ayUserRepository.save(ayUser);
}
@Override
public void delete(String id) {
ayUserRepository.deleteById(id);
}
//翻页
@Override
public Page<AyUser> findAll(Pageable pageable) {
return ayUserRepository.findAll(pageable);
}
@Override
public List<AyUser> findByName(String name) {
return ayUserRepository.findByName(name);
}
@Override
public List<AyUser> findByNameLike(String name) {
return ayUserRepository.findByNameLike(name);
}
@Override
public List<AyUser> findByIdIn(Collection<String> ids) {
return ayUserRepository.findByIdIn(ids);
}
}
第五步,使用JPA进行增删改查
@Resource
private AyUserService ayUserService;
@Test
public void testRepository(){
List<AyUser> userList = ayUserService.findAll();
System.out.println("findAll():"+userList.size());
List<AyUser> userList2 = ayUserService.findByName("文鹏");
System.out.println("findByName():"+userList2.size());
Assert.isTrue(userList2.get(0).getName().equals(("文鹏")));
List<AyUser> userList3 = ayUserService.findByNameLike("文%");
System.out.println("findByNameLike():"+userList3.size());
Assert.isTrue(userList3.get(0).getName().equals(("文鹏")));
List<String> ids = new ArrayList<String>();
ids.add("1");
ids.add("2");
List<AyUser> userList4 = ayUserService.findByIdIn(ids);
System.out.println("findByIdIn:"+userList4.size());
PageRequest pageRequest = PageRequest.of(0,10);
Page<AyUser> userList5 = ayUserService.findAll(pageRequest);
System.out.println("page findAll:"+userList5.getTotalPages()+"/"+userList5.getSize());
List<AyUser> userList6 = ayUserService.findByNameLike("%国%");
System.out.println("findByNameLike():"+userList6.size());
Assert.isTrue(userList6.get(0).getName().equals(("文国平")));
AyUser ayUser = new AyUser();
ayUser.setId("4");
ayUser.setName("李国正");
ayUser.setPassword("123");
ayUserService.save(ayUser);
List<AyUser> userList7 = ayUserService.findByNameLike("%国%");
System.out.println("findByNameLike():"+userList7.size());
Assert.isTrue(userList7.get(0).getName().equals(("文国平")));
ayUserService.delete("4");
List<AyUser> userList8 = ayUserService.findByNameLike("%国%");
System.out.println("findByNameLike():"+userList8.size());
Assert.isTrue(userList8.get(0).getName().equals(("文国平")));
}
事务是我们数据库操作的重要组成部分,有很多业务场景需要事务的原子性,一致性,隔离性和持久性。
SpringBoot同时支持编程式事务管理和声明式事务管理。编程式需要每个方法中额外增加提交和回滚动作,Spring推荐采用声明式事务管理,并通过内置的Spring AOP切片框架支持。
那么通过SpringDataJPA如何实现事务?
SpringBoot默认开启了JPA,JDBC,MyBatis的事务,无需我们做任何多余的配置。我们只需要对要起开事务的类或方法添加@Transactional注解即可。
@Transactional
@Service
public class AyUserServiceImpl implements AyUserService {
@Transactional
@Override
public void delete(String id) {
ayUserRepository.deleteById(id);
String e = null;
e.split("/");
}
}
@Transactional注解可以通过参数propagation定义事务的传播级别,也可以通过参数isolation隔离级别。
@Transactional(propagation=Propagation.REQUIRED) //控制事务传播。默认是Propagation.REQUIRED
@Transactional(isolation=Isolation.DEFAULT) //控制事务隔离级别。默认跟数据库的默认隔离级别相同
@Transactional(readOnly=false) //控制事务可读写还是只可读。默认可读写
@Transactional(timeout=30) //控制事务的超时时间,单位秒。默认跟数据库的事务控制系统相同,又说是30秒
@Transactional(rollbackFor=RuntimeException.class) //控制事务遇到哪些异常才会回滚。默认是RuntimeException
@Transactional(rollbackForClassName=RuntimeException) //同上
@Transactional(noRollbackFor=NullPointerException.class) //控制事务遇到哪些异常不会回滚。默认遇到非RuntimeException不会回滚
@Transactional(noRollbackForClassName=NullPointerException)//同上
具体可参考文章: