zoukankan      html  css  js  c++  java
  • MyBatis(六)MyBatis使用事务

    什么是事务

    • 可以把一系列要执行的操作称为事务,而事务管理就是管理这些操作要么完全执行,要么完全不执行(很经典的一个例子是: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 的记录,当前不存在。

    更多理论请查看:

    mysql之事务管理 - 随风行云 - 博客园 (cnblogs.com)

    JDBC介绍和Mybatis运行原理及事务处理 - rayallenbj - 博客园 (cnblogs.com)

  • 相关阅读:
    扩展欧几里得算法
    Warshall算法
    自己的博客
    使用forever运行web项目
    C#语言基础 Main 函数中的输出输入
    新手第一天学习 C#语言(进制互换)
    Django + Uwsgi + Nginx 实现生产环境部署1
    基于Flask的web微信
    python保存文件UnicodeEncodeError以及reload(sys)后print失效问题
    轮询/长轮询
  • 原文地址:https://www.cnblogs.com/qs315/p/15722594.html
Copyright © 2011-2022 走看看