在实际的运用开发中,跟数据库之间的交互是必不可少的,SpringBoot也提供了两种跟数据库交互的方式。

1. 使用JdbcTemplate

  在SpringBoot中提供了JdbcTemplate模板类,JdbcTemplate提供的方法进行增删改查的操作。

  首先需要在pom文件中添加依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

  还需要在application.properties中配置数据源。

spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_study
spring.datasource.username=username
spring.datasource.password=username
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

  在项目中顶一个dao,entity,service,controller层,添加一个实体类User和dao中的UserDAO接口,并实现它,具体代码如下:

  User.java

package com.wangx.boot.entity;

import java.io.Serializable;

public class User implements Serializable {

    private Integer id;
private String name;
private Integer age; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
}
}

使用jdbcTemplate必须实现Serializable接口,否则会出现异常。

  UserDAO的实现类UserDAOImpl.java

  UserDAOImpl.java

package com.wangx.boot.dao.impl;

import com.wangx.boot.dao.UserDAO;
import com.wangx.boot.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository; import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List; @Repository
public class UserDAOImpl implements UserDAO { @Autowired
private JdbcTemplate jdbcTemplate;
@Override
public Integer insert(User user) {
String sql = "insert into tb_user(name, age) values(?,?)";
return jdbcTemplate.update(sql, user.getName(), user.getAge());
} @Override
public List<User> findUserById(Integer id) {
String sql = "select * from tb_user where id = ?";
return jdbcTemplate.query(sql,new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
user.setName(resultSet.getString("name"));
user.setId(resultSet.getInt("id"));
user.setAge(resultSet.getInt("age"));
return user;
}
},id);
}
}

  使用@Repository讲该类管理到Bean中,使用时直接注入该bean,调用方法即可进行添加和查询的操作。jdbcTemplate中提供了增删改查,和带条件查询等支持,每种方法的具体使用方式可以自行看源码或官网demo。

2. 使用JPA

  SpringBoot的jpa继承hibernate和JdbcTemplate对数据库进行操作。

  使用jpa也有一些配置:

  可以取自己需要的配置在application.properties中配置。示例时使用了

spring.jpa.hibernate.ddl-auto=update//每次使用都检查表,没有表时会新建一张表
spring.jpa.show-sql=true //打印sql语句

  新建一个Book实体类:

package com.wangx.boot.entity;

import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Book { @Id
private int id;
private String name;
private String author; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getAuthor() {
return author;
} public void setAuthor(String author) {
this.author = author;
} @Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
}

  新建一个接口BookDAO继承JpaRepository<Book, Integer>,这里的第一个泛型为实体类型,第二个为主键类型:

  

package com.wangx.boot.dao.impl;

import com.wangx.boot.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import java.util.List;
public interface BookDAO extends JpaRepository<Book, Integer> { /**
* 根据属性名生成对应的方法名生成对应查询条件的方法
* @param name
* @return
*/
Book findByName(String name); /**
* 自定义sql语句
* @param name
* @return
*/
@Query(value = "select b from Book b where b.name=?1")
List<Book> findByBookName(String name);
}

  JpaRepository接口中提供很多增删改查的方法,使用时可以不在BookDAO中定一而直接使用jpa中的方法。

  测试该DAO的测试类

package com.wangx.boot;

import com.wangx.boot.dao.impl.BookDAO;
import com.wangx.boot.entity.Book;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootDemo03ApplicationTests {
@Autowired
private BookDAO bookDAO;
@Test
public void insert() {
Book book = new Book();
book.setAuthor("辰东");
book.setId(1);
book.setName("完美世界");
//测试jpa中默认的save方法,当配置了spring.jpa.hibernate.ddl-auto=update后,第一次使用时,当数据库中没有这张表时会自动新建表
System.out.println(bookDAO.save(book));
} @Test
public void find() {
//测试jpa中定义的根据id查询的方法
System.out.println(bookDAO.findById(0));
} @Test
public void findByName() {
//jpa提供了findByXxx根据属性名查找的方法。自动根据该方法名中的属性名生成对应条件的sql
System.out.println(bookDAO.findByName("遮天"));
} @Test
public void findByBookName() {
//使用@Query注解定一自己的sql语句
System.out.println(bookDAO.findByBookName("遮天"));
} @Test
public void findByPage() {
//使用分页查询
Pageable pageable = new QPageRequest(0,10);
Page<Book> bookPage = bookDAO.findAll(pageable);
List<Book> bookList = bookPage.getContent();
for (Book book : bookList) {
System.out.println(book);
}
} }

3. SpringBoot整合mybatis

  SpringBoot真的简化了很大开发量,接下来看看SpringBoot中使用mybaits的示例。

  引入mybatis依赖

  pom.xml

 <dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

  配置数据源,前面已经介绍就不再重复了,接下来配置mybatis一些文件路径

# 配置mybatis的映射文件路径,在我的工程里是classpath下的conf下的所有的.xml文件
mybatis.mapper-locations=classpath:/conf/*.xml
# 配置实体类的包路径
mybatis.type-aliases-package=com.wangx.boot.entity

  接下来看conf/下的userMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.wangx.boot.dao.UserDAO" >
<resultMap id="BaseResultMap" type="com.wangx.boot.entiry.User" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="age" property="age" jdbcType="INTEGER" />
</resultMap> <insert id="insert" parameterType="com.wangx.boot.entiry.User">
insert into tb_user(name,age) values (#{name}, #{age});
</insert> <select id="selectById" resultMap="BaseResultMap" parameterType="INTEGER">
select * from tb_user where id = #{id}
</select> <select id="selectAll" resultMap="BaseResultMap">
select * from tb_user
</select>
</mapper>

  这里定义了三个语句,对应dao层接口的三个方法,一个新增,两个查询,namespace一定要对应dao层中DAO的全名称。如这里的com.wangx.boot.UserDAO。每个查询语句对应DAO中相对应的方法,UserDAO如下:

package com.wangx.boot.dao;

import com.wangx.boot.entiry.User;

import java.util.List;

public interface UserDAO {

    Integer insert(User user);

    User selectById(Integer id);

    List<User> selectAll();
}

  在这里需要在springBoot启动类中添加@MapperScan("com.wangx.boot.dao")注解,扫描持久层接口路径。否则会找不到bean,在Service中调用UserDAO

package com.wangx.boot.service.impl;

import com.wangx.boot.dao.UserDAO;
import com.wangx.boot.entiry.User;
import com.wangx.boot.service.UserService;
import org.springframework.stereotype.Service; import javax.annotation.Resource;
import java.util.List; @Service
public class UserServiceImpl implements UserService { @Resource
private UserDAO userDAO; @Override
public Integer insert(User user) {
return userDAO.insert(user);
} @Override
public User selectById(Integer id) {
return userDAO.selectById(id);
} @Override
public List<User> selectAll() {
return userDAO.selectAll();
}
}

  测试:

package com.wangx.boot;

import com.wangx.boot.entiry.User;
import com.wangx.boot.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootDemo03ApplicationTests { @Autowired
private UserService userService;
@Test
public void contextLoads() {
User user = new User(); user.setName("张三");
user.setAge(30); System.out.println(userService.insert(user));
} @Test
public void selectById() {
User user = userService.selectById(2);
System.out.println(user);
} @Test
public void selectAll() {
List<User> users = userService.selectAll();
System.out.println(users);
}
}

  一个添加方法和两个查询方法均测试通过,修改和删除感兴趣的话可以自行编写。

4. 事务处理

  在SpringBoot中可以使用@Transaction注解对方法或类进行事务处理,作用于方法上的demo。

package com.wangx.boot.service;

import com.wangx.boot.dao.UserDAO;
import com.wangx.boot.dao.impl.BookDAO;
import com.wangx.boot.entity.Book;
import com.wangx.boot.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; @Service("userAndBookService")
public class UserAndBookService { @Autowired
private BookDAO bookDAO;
@Autowired
private UserDAO userDAO; @Transactional
public String add () {
User user = new User();
user.setName("夏利");
user.setAge(30);
userDAO.insert(user);
boolean flag = true;
if (flag) {
throw new RuntimeException();
}
Book book = new Book();
book.setId(3);
book.setName("圣墟");
book.setAuthor("辰东");
return "success";
}
}

  当第一个添加成功后,认为的抛出异常,查看数据库会发现两张表都没有添加成功。这就是使用@Transactional注解后抛异常时进行了事务回滚。因为Service层是处理整个逻辑的,所以事务的处理一般放在整个service层中,这样可以保证整个业务逻辑的一致性。

  下面来看一下事务的一下概念和@Transaction注解的一些属性的作用

  4.1 数据库的四个特性

  ⑴ 原子性(Atomicity)

  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

  ⑵ 一致性(Consistency)

  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

  拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

  ⑶ 隔离性(Isolation)

  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

  即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

  关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。

  ⑷ 持久性(Durability)

  持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

  4.2 Spring定义了七种传播行为

  1.PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

  2.PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。

  3.PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。

  4.PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。

  5.PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  6.PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。

  7.PROPAGATION_NESTED – 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
  常用的传播行为是1和4

  4.3 Spring中@Transaction注解的属性

  propagation:事务传播行为。

  isolation:事务隔离级别。

  readOnly:事务的读写性,boolean型。

  timeout:超时时间,int型,以秒为单位。

  rollbackFor:一组异常类,遇到时回滚。(rollbackFor={SQLException.class})。

  rollbackForCalssName:一组异常类名,遇到回滚,类型为string[]。

  noRollbackFor:一组异常类,遇到不回滚。

  norollbackForCalssName:一组异常类名,遇到时不回滚  

  4.4 五大隔离级别

  ISOLATION_DEFAULT
  这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.

  另外四个与JDBC的隔离级别相对应;

  ISOLATION_READ_UNCOMMITTED
  这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。
  这种隔离级别会产生脏读,不可重复读和幻像读。

  ISOLATION_READ_COMMITTED
  保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
  这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

  ISOLATION_REPEATABLE_READ
  这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
  它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。

  ISOLATION_SERIALIZABLE
  这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
  除了防止脏读,不可重复读外,还避免了幻像读。

  关键词:

    脏读:指一个事务读取了一个未提交事务的数据

    不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同.一个事务读取到了另一个事务提交后的数据.

    虚读(幻读):在一个事务内读取了别的事务插入的数据,导致前后读取不一致(insert)

  

SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理的更多相关文章

  1. SpringBoot学习笔记(11)-----SpringBoot中使用rabbitmq,activemq消息队列和rest服务的调用

    1. activemq 首先引入依赖 pom.xml文件 <dependency> <groupId>org.springframework.boot</groupId& ...

  2. SpringBoot学习笔记(10)-----SpringBoot中使用Redis/Mongodb和缓存Ehcache缓存和redis缓存

    1. 使用Redis 在使用redis之前,首先要保证安装或有redis的服务器,接下就是引入redis依赖. pom.xml文件如下 <dependency> <groupId&g ...

  3. SpringBoot学习笔记(6)----SpringBoot中使用Servlet,Filter,Listener的三种方式

    在一般的运用开发中Controller已经大部分都能够实现了,但是也不排除需要自己实现Servlet,Filter,Listener的方式,SpringBoot提供了三种实现方式. 1. 使用Bean ...

  4. SpringBoot学习笔记(4)----SpringBoot中freemarker、thymeleaf的使用

    1. freemarker引擎的使用 如果你使用的是idea或者eclipse中安装了sts插件,那么在新建项目时就可以直接指定试图模板 如图: 勾选freeMarker,此时springboot项目 ...

  5. SpringBoot学习笔记(5)----SpringBoot中异常处理的三种方法

    对于异常的处理,Spring Boot中提供默认的一个异常处理界面,如下图: 但是在实际的运用开发中,这样的页面显然是不友好的,Spring Boot也提供了自定义异常处理的方式,如下总结三种一场处理 ...

  6. SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]

    https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...

  7. springboot学习笔记-5 springboot整合shiro

    shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/  它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和sh ...

  8. springboot学习笔记-6 springboot整合RabbitMQ

    一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...

  9. 【转】SpringBoot学习笔记(7) SpringBoot整合Dubbo(使用yml配置)

    http://blog.csdn.net/a67474506/article/details/61640548 Dubbo是什么东西我这里就不详细介绍了,自己可以去谷歌 SpringBoot整合Dub ...

随机推荐

  1. JS应用实例1:表格各行换色

    效果如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  2. 对ListView的Item子控件监听并跳转页面

    public class MyAdapteforOwner extends BaseAdapter{ List<OwnerDevice>datas; private Context con ...

  3. Ubuntu 16.04安装Caffe的记录及FCN官方代码的配置

    相关内容搜集自官方文档与网络,既无创新性,也不求甚解,我也不了解Caffe,仅仅搭上之后做个记录,方便以后重装 安装依赖项sudo apt-get install libprotobuf-dev li ...

  4. Unity中 Animator 与Animation 区别

    ①Animation和Animator 虽然都是控制动画的播放,但是它们的用法和相关语法都是大有不同的.Animation 控制一个动画的播放,而Animator是多个动画之间相互切换,并且Anima ...

  5. https://blog.csdn.net/sxf359/article/details/71082404

    https://blog.csdn.net/sxf359/article/details/71082404

  6. javscript中变量的作用域和提升

    示例: var a = 1; function foo() {   if (!a) {     var a = 10;   }    alert(a); }; foo(); 上面这段代码在运行时会产生 ...

  7. Qwiklab'实验-CloudFront, EFS, S3'

    title: AWS之Qwiklab subtitle: 3. Qwiklab'实验-CloudFront, EFS, S3' date: 2018-09-21 17:29:20 --- Introd ...

  8. day16 闭包以及装饰器(好东西)

    目录 闭包 装饰器 最基础的装饰器 完善装饰器 有返回值的 有参数的 装饰器模版 语法糖 登录装饰器 可变类型的局部变量可以修改全局变量 三层装饰器 闭包 首先要理解函数对象的概念,其实函数名就相当于 ...

  9. python安装Redis数据库

    where pip cd 切换这个目录 pip install redis import redis r = redis.Redis(host='127.0.0.1', port=6379) user ...

  10. 广义线性模型------逻辑回归和softmax回归

    1.广义线性模型 2.逻辑回归 3.softmax回归