mybatis中连接池与事务

mybatis中的链接池

关于连接池

对于链接池,大家应该都不陌生,工程中不免存在许多需要访问数据的请求(访问服务、数据库、缓存等),对于这些下游服务,官方会提供不同语言的Driver、Document、DemoCode来指导使用方建立连接与接口调用。基本的通讯步骤为:建立连接、发送请求、关闭连接释放资源。对于并发量很低的请求,连接可以临时建立,但是当服务吞吐量非常大,建立连接connect和销毁连接close就会成为瓶颈,为了对其进行优化,连接池出现了。

通过链接池,请求的通讯步骤变为:从池中取出链接、发送请求、放回链接。

连接池核心原理与实现

数据库操作伪代码
DBClientConnection* c = ConnectionPool::GetConnection();

c->insert(“db.s”, BSON(”shenjian”));

ConnectionPool::FreeConnection(c);

可以看到连接池ConnectionPool主要有三个核心接口:

(1)Init:初始化Array[DBClientConnection],这个接口只在服务启动时调用一次;

(2)GetConnection:请求每次需要访问数据库时,不connect一个新连接,而是通过连接池的这个接口来拿连接;

(3)FreeConnection:请求每次访问完数据库时,不是close一个连接,而是把这个连接放回连接池;

通俗的讲,连接池就是用于存储链接的一个容器,容器其实就是一个集合对象,并且该集合必须是线程安全的,不能两个线程拿到同一个链接。该集合还必须实现队列的特性,先进先出。

mybatis中的链接池

几种连接池介绍

在mybatis中,含有以下几类连接池:
在这里插入图片描述
在这里插入图片描述
pooled:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现。
unpooled:采用传统的获取连接的方式,虽然也实现javax.sql.DataSource接口,但是并没有使用池的思想。
jndi:采用服务器提供的jndi技术实现,来获取DataSource对象,不同的服务器所能拿到的DataSource是不一样的。

在这三种数据源中,我们一般采用的是 POOLED 数据源。

mybatis中连接池配置

在 Mybatis 的 SqlMapConfig.xml 配置文件中,通过来实现 Mybatis 中连接池的配置。type属性就是表示采用何种链接池方式。

<!-- 配置数据源(连接池)信息 -->
<dataSource type="POOLED">
	<property name="driver" value="com.mysql.jdbc.Driver"/>
	<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
	<property name="username" value="root"/>
	<property name="password" value="1234"/>
</dataSource>

当然如果配置了properties标签,可以进行连接信息的抽离:

<properties resource="dbconfig.properties"></properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即:type=”POOLED”:MyBatis 会创建 PooledDataSource 实例,然后返回使用。

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

//DataSourceFactory源码
package org.apache.ibatis.datasource;
import java.util.Properties;
import javax.sql.DataSource;
/**
* @author Clinton Begin
*/
public interface DataSourceFactory {
	void setProperties(Properties props);
	DataSource getDataSource();
}

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

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

@Test
public void testSql() throws Exception {
	InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
	SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
	SqlSession sqlSession = factory.openSession();
	List<User> list = sqlSession.selectList("findUserById",41);
	System.out.println(list.size());
}

只有当第 4 句sqlSession.selectList(“findUserById”),才会触发 MyBatis 在底层执行下面这个方法来创建 java.sql.Connection 对象。

数据库连接是我们最为宝贵的资源,只有在要用到的时候,才去获取并打开连接,当我们用完了就再立即将数据库连接归还到连接池中。

mybatis中的事务

对于增删改操作,并不是读到语句后就立马对数据库数据进行更新,而是通过建立连接,每建立一次连接,并且这些操作在同一个连接内,那么在语句执行完毕后,这些增删改操作将会被一起提交到数据库中执行

而对于select语句,在语句关联结果集关闭时,也就是本条查询语句已经明确将查询结果付给什么变量时,就会向数据库中提交一次执行

以上这些是JDBC的默认提交时间。

在 JDBC 中我们可以自行将事务的提交改为手动方式,通过setAutoCommit()方法就可以调整。也就是当我们在新建立连接时,可以根据传入参数的不同,说明本次连接时自动提交还是手动提交。
在这里插入图片描述
那么我们的 Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC的setAutoCommit()方法来设置事务提交方式的。

Mybatis 手动提交事务

@Test
public void testSaveUser() throws Exception {
	User user = new User();
	user.setUsername("mybatis user09");
	
	//6.执行操作
	int res = userDao.saveUser(user);
	System.out.println(res);
	System.out.println(user.getId());
}

@Before//在测试方法执行之前执行
public void init()throws Exception {
	//1.读取配置文件
	in = Resources.getResourceAsStream("SqlMapConfig.xml");
	
	//2.创建构建者对象
	SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
	
	//3.创建 SqlSession 工厂对象
	factory = builder.build(in);
	
	//4.创建 SqlSession 对象
	session = factory.openSession();
	
	//5.创建 Dao 的代理对象
	userDao = session.getMapper(IUserDao.class);
}

@After//在测试方法执行完成之后执行
public void destroy() throws Exception{
	//7.提交事务
	session.commit();
	//8.释放资源
	session.close();
	in.close();
}

以上在创建连接时:session=factory.openSession();没有传入参数,这样一来连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,这样我们就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit()方法实现事务提交。

Mybatis 自动动提交事务

@Before//在测试方法执行之前执行
public void init()throws Exception {
	//1.读取配置文件
	in = Resources.getResourceAsStream("SqlMapConfig.xml");
	
	//2.创建构建者对象
	SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
	
	//3.创建 SqlSession 工厂对象
	factory = builder.build(in);
	
	//4.创建 SqlSession 对象,传入参数为true,代表开启自动提交
	session = factory.openSession(true);
	
	//5.创建 Dao 的代理对象
	userDao = session.getMapper(IUserDao.class);
}

@After//在测试方法执行完成之后执行
public void destroy() throws Exception{
	//7.释放资源
	session.close();
	in.close();
}

此时事务就设置为自动提交了,同样可以实现CUD操作时记录的保存。虽然这也是一种方式,但就编程而言,设置为自动提交方式为 false再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章