javascript
SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理
在實(shí)際的運(yùn)用開發(fā)中,跟數(shù)據(jù)庫(kù)之間的交互是必不可少的,SpringBoot也提供了兩種跟數(shù)據(jù)庫(kù)交互的方式。
1. 使用JdbcTemplate
在SpringBoot中提供了JdbcTemplate模板類,JdbcTemplate提供的方法進(jìn)行增刪改查的操作。
首先需要在pom文件中添加依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>還需要在application.properties中配置數(shù)據(jù)源。
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在項(xiàng)目中頂一個(gè)dao,entity,service,controller層,添加一個(gè)實(shí)體類User和dao中的UserDAO接口,并實(shí)現(xiàn)它,具體代碼如下:
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必須實(shí)現(xiàn)Serializable接口,否則會(huì)出現(xiàn)異常。
UserDAO的實(shí)現(xiàn)類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中,使用時(shí)直接注入該bean,調(diào)用方法即可進(jìn)行添加和查詢的操作。jdbcTemplate中提供了增刪改查,和帶條件查詢等支持,每種方法的具體使用方式可以自行看源碼或官網(wǎng)demo。
2. 使用JPA
SpringBoot的jpa繼承hibernate和JdbcTemplate對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作。
使用jpa也有一些配置:
可以取自己需要的配置在application.properties中配置。示例時(shí)使用了
spring.jpa.hibernate.ddl-auto=update//每次使用都檢查表,沒有表時(shí)會(huì)新建一張表 spring.jpa.show-sql=true //打印sql語句新建一個(gè)Book實(shí)體類:
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 + '\'' + '}'; } }新建一個(gè)接口BookDAO繼承JpaRepository<Book, Integer>,這里的第一個(gè)泛型為實(shí)體類型,第二個(gè)為主鍵類型:
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> { /** * 根據(jù)屬性名生成對(duì)應(yīng)的方法名生成對(duì)應(yīng)查詢條件的方法 * @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接口中提供很多增刪改查的方法,使用時(shí)可以不在BookDAO中定一而直接使用jpa中的方法。
測(cè)試該DAO的測(cè)試類
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("完美世界"); //測(cè)試jpa中默認(rèn)的save方法,當(dāng)配置了spring.jpa.hibernate.ddl-auto=update后,第一次使用時(shí),當(dāng)數(shù)據(jù)庫(kù)中沒有這張表時(shí)會(huì)自動(dòng)新建表 System.out.println(bookDAO.save(book)); } @Test public void find() { //測(cè)試jpa中定義的根據(jù)id查詢的方法 System.out.println(bookDAO.findById(0)); } @Test public void findByName() { //jpa提供了findByXxx根據(jù)屬性名查找的方法。自動(dòng)根據(jù)該方法名中的屬性名生成對(duì)應(yīng)條件的sql System.out.println(bookDAO.findByName("遮天")); } @Test public void findByBookName() { //使用@Query注解定一自己的sql語句 System.out.println(bookDAO.findByBookName("遮天")); } @Test public void findByPage() { //使用分頁(yè)查詢 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真的簡(jiǎn)化了很大開發(fā)量,接下來看看SpringBoot中使用mybaits的示例。
引入mybatis依賴
pom.xml
<dependency><groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency>配置數(shù)據(jù)源,前面已經(jīng)介紹就不再重復(fù)了,接下來配置mybatis一些文件路徑
# 配置mybatis的映射文件路徑,在我的工程里是classpath下的conf下的所有的.xml文件 mybatis.mapper-locations=classpath:/conf/*.xml # 配置實(shí)體類的包路徑 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>這里定義了三個(gè)語句,對(duì)應(yīng)dao層接口的三個(gè)方法,一個(gè)新增,兩個(gè)查詢,namespace一定要對(duì)應(yīng)dao層中DAO的全名稱。如這里的com.wangx.boot.UserDAO。每個(gè)查詢語句對(duì)應(yīng)DAO中相對(duì)應(yīng)的方法,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啟動(dòng)類中添加@MapperScan("com.wangx.boot.dao")注解,掃描持久層接口路徑。否則會(huì)找不到bean,在Service中調(diào)用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(); } }測(cè)試:
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); } }一個(gè)添加方法和兩個(gè)查詢方法均測(cè)試通過,修改和刪除感興趣的話可以自行編寫。
4. 事務(wù)處理
在SpringBoot中可以使用@Transaction注解對(duì)方法或類進(jìn)行事務(wù)處理,作用于方法上的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"; } }當(dāng)?shù)谝粋€(gè)添加成功后,認(rèn)為的拋出異常,查看數(shù)據(jù)庫(kù)會(huì)發(fā)現(xiàn)兩張表都沒有添加成功。這就是使用@Transactional注解后拋異常時(shí)進(jìn)行了事務(wù)回滾。因?yàn)镾ervice層是處理整個(gè)邏輯的,所以事務(wù)的處理一般放在整個(gè)service層中,這樣可以保證整個(gè)業(yè)務(wù)邏輯的一致性。
下面來看一下事務(wù)的一下概念和@Transaction注解的一些屬性的作用
4.1 數(shù)據(jù)庫(kù)的四個(gè)特性
⑴ 原子性(Atomicity)
原子性是指事務(wù)包含的所有操作要么全部成功,要么全部失敗回滾,這和前面兩篇博客介紹事務(wù)的功能是一樣的概念,因此事務(wù)的操作如果成功就必須要完全應(yīng)用到數(shù)據(jù)庫(kù),如果操作失敗則不能對(duì)數(shù)據(jù)庫(kù)有任何影響。
⑵ 一致性(Consistency)
一致性是指事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變換到另一個(gè)一致性狀態(tài),也就是說一個(gè)事務(wù)執(zhí)行之前和執(zhí)行之后都必須處于一致性狀態(tài)。
拿轉(zhuǎn)賬來說,假設(shè)用戶A和用戶B兩者的錢加起來一共是5000,那么不管A和B之間如何轉(zhuǎn)賬,轉(zhuǎn)幾次賬,事務(wù)結(jié)束后兩個(gè)用戶的錢相加起來應(yīng)該還得是5000,這就是事務(wù)的一致性。
⑶ 隔離性(Isolation)
隔離性是當(dāng)多個(gè)用戶并發(fā)訪問數(shù)據(jù)庫(kù)時(shí),比如操作同一張表時(shí),數(shù)據(jù)庫(kù)為每一個(gè)用戶開啟的事務(wù),不能被其他事務(wù)的操作所干擾,多個(gè)并發(fā)事務(wù)之間要相互隔離。
即要達(dá)到這么一種效果:對(duì)于任意兩個(gè)并發(fā)的事務(wù)T1和T2,在事務(wù)T1看來,T2要么在T1開始之前就已經(jīng)結(jié)束,要么在T1結(jié)束之后才開始,這樣每個(gè)事務(wù)都感覺不到有其他事務(wù)在并發(fā)地執(zhí)行。
關(guān)于事務(wù)的隔離性數(shù)據(jù)庫(kù)提供了多種隔離級(jí)別,稍后會(huì)介紹到。
⑷ 持久性(Durability)
持久性是指一個(gè)事務(wù)一旦被提交了,那么對(duì)數(shù)據(jù)庫(kù)中的數(shù)據(jù)的改變就是永久性的,即便是在數(shù)據(jù)庫(kù)系統(tǒng)遇到故障的情況下也不會(huì)丟失提交事務(wù)的操作。
4.2 Spring定義了七種傳播行為
1.PROPAGATION_REQUIRED – 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。這是最常見的選擇。
2.PROPAGATION_SUPPORTS – 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
3.PROPAGATION_MANDATORY – 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
4.PROPAGATION_REQUIRES_NEW – 新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
5.PROPAGATION_NOT_SUPPORTED – 以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
6.PROPAGATION_NEVER – 以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
7.PROPAGATION_NESTED – 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則進(jìn)行與PROPAGATION_REQUIRED類似的操作。
常用的傳播行為是1和4
4.3 Spring中@Transaction注解的屬性
propagation:事務(wù)傳播行為。
isolation:事務(wù)隔離級(jí)別。
readOnly:事務(wù)的讀寫性,boolean型。
timeout:超時(shí)時(shí)間,int型,以秒為單位。
rollbackFor:一組異常類,遇到時(shí)回滾。(rollbackFor={SQLException.class})。
rollbackForCalssName:一組異常類名,遇到回滾,類型為string[]。
noRollbackFor:一組異常類,遇到不回滾。
norollbackForCalssName:一組異常類名,遇到時(shí)不回滾
4.4 五大隔離級(jí)別
ISOLATION_DEFAULT
這是一個(gè)PlatfromTransactionManager默認(rèn)的隔離級(jí)別,使用數(shù)據(jù)庫(kù)默認(rèn)的事務(wù)隔離級(jí)別.
另外四個(gè)與JDBC的隔離級(jí)別相對(duì)應(yīng);
ISOLATION_READ_UNCOMMITTED
這是事務(wù)最低的隔離級(jí)別,它充許別外一個(gè)事務(wù)可以看到這個(gè)事務(wù)未提交的數(shù)據(jù)。
這種隔離級(jí)別會(huì)產(chǎn)生臟讀,不可重復(fù)讀和幻像讀。
ISOLATION_READ_COMMITTED
保證一個(gè)事務(wù)修改的數(shù)據(jù)提交后才能被另外一個(gè)事務(wù)讀取。另外一個(gè)事務(wù)不能讀取該事務(wù)未提交的數(shù)據(jù)。
這種事務(wù)隔離級(jí)別可以避免臟讀出現(xiàn),但是可能會(huì)出現(xiàn)不可重復(fù)讀和幻像讀。
ISOLATION_REPEATABLE_READ
這種事務(wù)隔離級(jí)別可以防止臟讀,不可重復(fù)讀。但是可能出現(xiàn)幻像讀。
它除了保證一個(gè)事務(wù)不能讀取另一個(gè)事務(wù)未提交的數(shù)據(jù)外,還保證了避免下面的情況產(chǎn)生(不可重復(fù)讀)。
ISOLATION_SERIALIZABLE
這是花費(fèi)最高代價(jià)但是最可靠的事務(wù)隔離級(jí)別。事務(wù)被處理為順序執(zhí)行。
除了防止臟讀,不可重復(fù)讀外,還避免了幻像讀。
關(guān)鍵詞:
臟讀:指一個(gè)事務(wù)讀取了一個(gè)未提交事務(wù)的數(shù)據(jù)
不可重復(fù)讀:在一個(gè)事務(wù)內(nèi)讀取表中的某一行數(shù)據(jù),多次讀取結(jié)果不同.一個(gè)事務(wù)讀取到了另一個(gè)事務(wù)提交后的數(shù)據(jù).
虛讀(幻讀):在一個(gè)事務(wù)內(nèi)讀取了別的事務(wù)插入的數(shù)據(jù),導(dǎo)致前后讀取不一致(insert)
?原文 SpringBoot學(xué)習(xí)筆記(9)----SpringBoot中使用關(guān)系型數(shù)據(jù)庫(kù)以及事務(wù)處理
轉(zhuǎn)載于:https://www.cnblogs.com/xiaoshen666/p/10844012.html
總結(jié)
以上是生活随笔為你收集整理的SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql gid_mysql主从复制5
- 下一篇: 色散方程用matlab编译,急切求助用m