九点钟☆方向

记录成长点滴

欢迎来到我的个人博客~


Mybatis笔记(六) Mybatis连接池与事务

目录

连接池

在实际开发中都会使用连接池,因为他可以减少我们获取连接所消耗的时间。连接池就是用于存储连接的一个容器,这个容器其实就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到同一个连接,该集合还必须实现队列的特点:先进先出。

Mybatis中的连接池

Mybatis连接池的分类

5

可以看出 Mybatis 将它自己的数据源分为三类:

  • UNPOOLED :不使用连接池的数据源
  • POOLED: 使用连接池的数据源
  • JNDI :使用 JNDI 实现的数据源

具体结构如下:

6

相应地, MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource, PooledDataSource 类来表示 UNPOOLED、 POOLED 类型的数据源

7

在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据 库连接,也就是我们所说的连接池技术) 。

Mybatis 中数据源的配置

我们的数据源配置就是在 SqlMapConfig.xml 文件中的<dataSource type=>, 具体配置如下:

  1. POOLED:MyBatis 会创建 PooledDataSource 实例,会采用传统的javax.sql.DataSource规范中的连接池,Mybatis有针对规范的实现,他是从池中获取一个连接来用

    <dataSource type="POOLED">
        <property name="driver" value=""></property>
        <property name="url" value=""></property>
        <property name="username" value=""></property>
        <property name="password" value=""></property>
     </dataSource>
    
  2. UNPOOLED:MyBatis 会创建 UnpooledDataSource 实例,虽然也实现了javax.sql.DataSource接口,但是 并没有使用池的思想,每次创建一个新的连接来用

    <dataSource type="UNPOOLED">
        <property name="driver" value=""></property>
        <property name="url" value=""></property>
        <property name="username" value=""></property>
        <property name="password" value=""></property>
    </dataSource>
    
  3. JNDI:是SUN公司推出的一套规范,属于JavaEE技术之一。目的是模仿windows系统中的注册表。采用服务器提供的JNDI技术实现,来获取DataSource对 象,不同的服务器所能拿到DataSource是不一样。 mybaties会从在应用服务器向配置好的JNDI数据源DataSource获取数据库连接。一般在生产环境中使用

    SqlMapConfig.xml中的配置:
    <!-- 配置环境 -->
        <environments default="mysql">
            <!-- 配置mysql环境 -->
            <environment id="mysql">
                <!-- 配置事务 -->
                <transactionManager type="JDBC"></transactionManager>
                <!-- 配置连接池 UNPOOLED POOLED JNDI -->
                <dataSource type="JNDI">
                    <property name="data_source"  value="java:comp/env/jdbc/text"/>
                </dataSource>
            </environment>
        </environments>
       
    以Tomcat为例,在Tomcat/conf/context.xml配置如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <Context>
        <Resource 
        name="jdbc/test"                  数据源的名称
        type="javax.sql.DataSource"       数据源类型
        auth="Container"                  数据源提供者
        maxActive="20"                    最大活动数
        maxWait="10000"                   最大等待时间
        maxIdle="5"                       最大空闲数
        username="root"                   用户名
        password="123"                    密码
        driverClassName="com.mysql.jdbc.Driver"    驱动类
        url="jdbc:mysql://localhost:3306/chatroom" 连接url字符串
    />
    

    注意:

    • 当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象 来创建java.sql.Connection对象。也就是说, java.sql.Connection对象的创建一直延迟到执行SQL语句 的时候。

    • MyBatis 是 通 过 工 厂 模 式 来 创 建 数 据 源 DataSource 对 象 的 , MyBatis 定 义 了 抽 象 的 工 厂 接 口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源 DataSource。

    • MyBatis 创建了 DataSource 实例后,会将其放到 Configuration 对象内的 Environment 对象中, 供 以后使用。

    • 图示:

      8

事务

什么是事务

所谓事务(Transaction ),是指一个操作序列,这些操作序列要么都被执行,要么都不被执行,它是一个不可分割的工作单元。

事务的四个特性(ACID)

  1. 原子性(Atomicity):操作这些指令时要么全部成功,要么全部失败,只要其中一个指令失败则全部指令执行失败,数据回滚。
  2. 一致性(Consistency):事务的执行使数据从一个状态转换成另一个状态,但是对于整个数据的完整性保持一致。例如,A和B两者共有1000元,无论转账几次,事务结束后总额还是1000元
  3. 隔离性(Isolation):当多个用户并发访问数据库时,数据库为每一个用户开启的事务不能被其他事务干扰,多个并发事务间要相互隔离
  4. 持久性(Durability):当事务正确完成后,他对于数据的改变是永久性的。

不考虑隔离性,并发事务会导致的三个问题

  1. 脏读:一个事务读取了另一个事务未提交的数据。例如:A对B转账,事务1执行了B+100,但是并未提交,此时事务2 读取了事务1 未提交的数据,显示B多了100。如果此时事务1进行了回滚,这时就造成了脏读。
  2. 不可重复读:在一个事务中读取两次某个数据,读出来的数据不一致。事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发生了不可重复读。
  3. 幻读:一个事务先后读取一个范围的记录,两次读取的记录不同。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读

注意:

  1. 脏读和不可重复读的区别:脏读是某一事务读取了另一事务未提交的数据;而不可重复读则是读取了另一事务提交的数据
  2. 幻读和不可重复读的区别:两者都是读取了另一个事务提交的数据,不同的是不可重复读读取的是同一个数据项,幻读针对的是一批数据整体,比如数据个数

解决方法(四种隔离级别)

  1. Read Uncommited(最低级别,任何情况都无法保证)

    读未提交。就是一个事务可以读取另一个未提交事务的数据

  2. Read Commited(可避免脏读)

    读提交。一个事务要等另一个事务提交后才能读取数据

  3. Repeatable Read(可避免脏读,不可重复读)

    重复读。在开始读取数据(事务开启)时,不再允许修改操作。重复读可以解决不可重复读问题。应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作

  4. Serializable(可避免脏读、不可重复读、幻读)

    Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

注意:

  1. 大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read。
  2. 隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。
  3. 设置数据库的隔离级别一定要是在开启事务之前。

Mybatis中的事务

他是通过SqlSession对象的commit()方法和rollback()方法实现事务的提交和回滚。底层都是JDBC的操作。因为在执行时Mybatis会设置setAutoCommit()为false,所以每次我们必须通过SqlSession.commit()手动提交。我们也可以设置自动提交,在获取SqlSession对象时:session = factory.openSession(true);这样就可以设置自动提交,但就编程而言,设置自动提交为false,再根据情况决定是否提交,这种方式更常用。

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦