MyBatis(六)MyBatis使用事務
阿新 • • 發佈:2021-12-23
什麼是事務
- 可以把一系列要執行的操作稱為事務,而事務管理就是管理這些操作要麼完全執行,要麼完全不執行(很經典的一個例子是:A要給B轉錢,首先A的錢減少了,但是突然的資料庫斷電了,導致無法給B加錢,然後由於丟失資料,B不承認收到A的錢;在這裡事務就是確保加錢和減錢兩個都完全執行或完全不執行,如果加錢失敗,那麼不會發生減錢)。
- 事務管理的意義:保證資料操作的完整性。
- mysql中並不是所有的資料引擎都支援事務管理的,只有innodb支援事務管理。
事務是指的是一個業務上的最小不可再分單元,通常一個事務對應了一個完整的業務,而一個完整的業務需要批量的DML語句共同聯合完成。一般,同一個事務中的SQL語句是儲存到資料庫中的同一個Transaction物件中,原因是Transaction具有一致性的特徵,也就是說事務中如果有任何一條sql語句執行失敗,那麼這個事務中所有的SQL語句都會被判定為無效SQL。
事務管理的特性
- 原子性(Atomicity):事務的整個操作是一個整體,不可以分割,要麼全部成功,要麼全部失敗。
- 一致性(Consistency):事務操作的前後,資料表中的資料沒有變化。
- 隔離性(Isolation):事務操作是相互隔離不受影響的。
- 永續性(Durability):資料一旦提交,不可改變,永久的改變資料表資料。
事務隔離級別
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
讀未提交(read-uncommitted)也叫髒讀 | 是 | 是 | 是 |
不可重複讀(read-committed)也叫讀已提交 | 否 | 是 | 是 |
可重複讀(repeatable-read)預設級別 | 否 | 否 | 是 |
序列化(serializable) | 否 | 否 | 否 |
使用JDBC的事務管理機制
在mybatis-config.xml中新增如下配置
<!-- mybatis使用jdbc事務管理方式 -->
<transactionManager type="jdbc"/>
子節點<transactionManager>
的type 會決定我們用什麼型別的事務管理機制。
完整配置如下
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 列印sql日誌 --> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/OrderMapper.xml"/> <mapper resource="mapper/UserMapper.xml"/> </mappers> </configuration>
事務的建立
建立事務
JdbcTransaction jdbcTransaction= new JdbcTransaction(getConnection());
完整程式碼如下
UserMapper
package org.mybatis.example;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper {
List<User> selectUserByListId(@Param("ids") List<Integer> ids);
List<User> selectUser(String username);
int insertUser(User user);
}
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="org.mybatis.example.UserMapper">
<!-- 一對多 根據id查詢使用者及其關聯的訂單資訊:級聯查詢的第一種方法(分步查詢) -->
<resultMap type="org.mybatis.example.User" id="myResult">
<id property="id" column="id" />
<result property="username" column="username" />
<result property="sex" column="sex" />
<result property="birthday" column="birthday" />
<result property="address" column="address" />
</resultMap>
<select id="selectUserByListId" parameterType="List" resultMap="myResult">
select * from user
<where>
<!--
collection:指定輸入物件中的集合屬性
item:每次遍歷生成的物件
open:開始遍歷時的拼接字串
close:結束時拼接的字串
separator:遍歷物件之間需要拼接的字串
select * from user where 1=1 and id in (1,2,3)
-->
<foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
#{id}
</foreach>
</where>
</select>
<select id="selectUser" resultMap="myResult">
<bind name="username" value="'%'+_parameter+'%'" />
select * from user where username like #{username}
</select>
<insert id="insertUser">
insert into user(username,sex,birthday,address) value(#{username},#{sex},#{birthday},#{address})
</insert>
</mapper>
MainApplication
package org.mybatis.example;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransaction;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
public class MainApplication {
public static void main(String[] args) throws IOException, SQLException {
InputStream config = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(config);
SqlSession ss = ssf.openSession();
JdbcTransaction jdbcTransaction= new JdbcTransaction(ss.getConnection());
try{
UserMapper userMapper = ss.getMapper(UserMapper.class);
User user = new User();
user.setAddress("地址1");
user.setUsername("使用者1");
userMapper.insertUser(user);
user.setUsername("使用者2");
userMapper.insertUser(user);
System.out.println("事務提交");
jdbcTransaction.commit();
}catch(Exception ex){
System.out.println("事務回滾");
jdbcTransaction.rollback();
throw ex;
}
}
}
執行MainApplication輸出如下
Opening JDBC Connection
Created connection 371439501.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1623b78d]
==> Preparing: insert into user(username,sex,birthday,address) value(?,?,?,?)
==> Parameters: 使用者1(String), null, null, 地址1(String)
<== Updates: 1
==> Preparing: insert into user(username,sex,birthday,address) value(?,?,?,?)
==> Parameters: 使用者2(String), null, null, 地址1(String)
<== Updates: 1
事務提交
Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1623b78d]
檢視資料庫
驗證是否正確,在插入第一條資料後報錯。
package org.mybatis.example;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransaction;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
public class MainApplication {
public static void main(String[] args) throws IOException, SQLException {
InputStream config = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(config);
SqlSession ss = ssf.openSession();
JdbcTransaction jdbcTransaction= new JdbcTransaction(ss.getConnection());
try{
UserMapper userMapper = ss.getMapper(UserMapper.class);
User user = new User();
user.setAddress("地址1");
user.setUsername("使用者3");
userMapper.insertUser(user);
int i = 1/0;
user.setUsername("使用者4");
userMapper.insertUser(user);
System.out.println("事務提交");
jdbcTransaction.commit();
}catch(Exception ex){
System.out.println("事務回滾");
jdbcTransaction.rollback();
throw ex;
}
}
}
執行如下,事務正常回滾。
Opening JDBC Connection
Created connection 371439501.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1623b78d]
==> Preparing: insert into user(username,sex,birthday,address) value(?,?,?,?)
==> Parameters: 使用者3(String), null, null, 地址1(String)
<== Updates: 1
事務回滾
Rolling back JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1623b78d]
Exception in thread "main" java.lang.ArithmeticException: / by zero
at org.mybatis.example.MainApplication.main(MainApplication.java:27)
檢視資料庫中是否存在 使用者3 的記錄,當前不存在。
更多理論請檢視: