为什么要编写工具类?
1. 代码复用
工具类集中封装了常用的功能和操作,比如创建和关闭 SqlSession
,这样可以避免在多个地方重复编写相同的代码。每次使用时,只需要调用工具类中的方法即可,简化了代码。
示例: 每次要打开 SqlSession
,如果没有工具类,就必须手动写以下代码:
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
有了工具类后,使用代码变得简单:
SqlSession sqlSession = SqlSessionUtil.openSession();
2. 集中管理资源
像 SqlSessionFactory
这样的资源通常是全局的,只有一个实例。在工具类中进行集中管理,确保整个应用程序中只创建一个 SqlSessionFactory
实例,避免资源浪费。此外,通过工具类也能更好地控制 SqlSession
的创建和关闭,确保资源不泄露。
好处:
- 避免了重复创建
SqlSessionFactory
带来的性能开销。 SqlSession
的关闭在工具类中进行统一管理,避免开发人员忘记关闭会话导致连接泄漏。
工具类
package Utils;
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 java.io.IOException;
import java.io.InputStream;
public class SqlSessionUtil {
// 静态SqlSessionFactory对象,用于保证整个应用程序中只有一个SqlSessionFactory实例
private static SqlSessionFactory sqlSessionFactory;
// 静态代码块,用于类加载时初始化SqlSessionFactory对象
static {
try {
// 读取MyBatis配置文件,构建SqlSessionFactory对象
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException(e); // 捕获IO异常并抛出运行时异常
}
}
/**
* 获取SqlSession对象
* @return SqlSession对象
*/
public static SqlSession openSession() {
// 使用SqlSessionFactory打开一个新的SqlSession
return sqlSessionFactory.openSession();
}
/**
* 关闭SqlSession对象
* @param sqlSession 要关闭的SqlSession对象
*/
public static void closeSession(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close(); // 关闭会话
}
}
}
代码解释
1. 静态代码块
静态代码块在类加载时执行一次,用于初始化类级别的静态变量。代码中使用静态代码块读取 MyBatis 的配置文件,构建 SqlSessionFactory
,确保应用中只有一个 SqlSessionFactory
实例。
2. 资源读取和配置文件
通过 Resources.getResourceAsStream("mybatis-config.xml")
来读取 MyBatis 的核心配置文件 mybatis-config.xml
,这个文件通常包含数据库连接信息、Mapper 映射、事务管理等配置。
3. 异常处理
在读取配置文件时,可能会发生 IOException
,此处捕获该异常,并抛出运行时异常 RuntimeException
,以防止系统继续执行。如果初始化失败,程序应立即停止。
4. 工具方法
SqlSessionUtil
提供了两个公共静态方法:
openSession()
:返回一个新的SqlSession
,用于执行数据库操作。closeSession(SqlSession sqlSession)
:关闭传入的SqlSession
,以释放数据库资源。
5. 单例模式
通过静态工厂(SqlSessionFactory
)实现单例模式,这样避免每次操作都重新创建工厂对象,提高了系统的性能和资源利用率。
扩展:为何要封装 SqlSession
?
- 保证全局唯一的
SqlSessionFactory
实例,减少资源浪费。 - 方便管理
SqlSession
的创建与关闭,确保数据库连接不被泄露。 - 集中管理异常处理,简化业务层的代码复杂度。
1. 一个数据库对应一个 SqlSessionFactory
通常,一个 SqlSessionFactory
对应一个数据库连接配置。这意味着,如果你的应用程序需要连接多个数据库,那么你通常会为每个数据库配置一个 SqlSessionFactory
实例。原因在于每个 SqlSessionFactory
会加载不同的数据库配置(例如,数据库的 URL、用户名、密码等)。
- 示例:假设你有两个数据库
db1
和db2
,你可能会创建两个SqlSessionFactory
实例,每个实例负责对应一个数据库的连接。SqlSessionFactory sqlSessionFactory1 = ... // 针对数据库 db1 SqlSessionFactory sqlSessionFactory2 = ... // 针对数据库 db2
2. 一个会话(SqlSession
)对应一次数据库操作
一个 SqlSession
通常用于处理一次数据库操作或事务。SqlSession
不是线程安全的,通常在每个线程中创建新的 SqlSession
,并在操作结束后关闭它。这样做的好处是:
- 每个
SqlSession
只负责一次数据库事务操作,使用完后及时关闭,避免连接泄漏。 - 一个
SqlSession
打开后,会绑定到一个特定的数据库连接,因此整个会话中涉及的操作都在这个连接上进行。
java的例子
package test;
import Utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.testng.annotations.Test;
public class CarMapperTest {
@Test
public void testInsertCarByUtil(){
SqlSession sqlSession = SqlSessionUtil.openSession();
int count = sqlSession.insert("insertCar");
sqlSession.commit();
sqlSession.close();
}
}