1.SqlSessionFactoryBuilder
利用xml或者Java编码获得资源来构建SqlSessionFactory,通过它可以构建多个SessionFactory。
其作用就是一个构建器,一旦构建了SqlSessionFactory,其作用就已经完结,此时应当对其进行回收。
所以其生命周期只存在于方法的局部,生成SqlSessionFactory
2.SqlSessionFactory
用于创建SqlSession(相当于jdbc的Connection)。
每次程序需要访问数据库时,都需要通过SqlSessionFactory创建SqlSession,所以SqlSessionFactory应该在Mybatis的整个生命周期中。
如果我们多次创建同一个数据库的SqlSessionFactory,则每次创建SqlSessionFactory会打开更多数据库链接,很快就会耗尽数据库资源,整个应用中只要有一个SqlSessionFactory就可以了,应当采用单例设计模式。
3.SqlSession(线程不安全)
其生命周期应该是在请求数据库处理事务的过程中。
通过其操作数据库时要注意其隔离级别和数据库锁等高级特性,每次使用完都需要即使关闭SqlSession,防止数据库的资源耗尽。
4.Mapper
其是一个interface,没有任何实现类,用于发送sql,返回我们需要的结果或者修改数据库中的数据,所以其应该存在于SqlSession事务方法之内,是一个方法级别的操作
工程目录结构
参考提供log4j.properties
log4j.rootLogger = DEBUG, stdout
log4j.logger.org.mybatis = DEBUG
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %5p %d %C: %m%n
下面是具体的配置截图
这里介绍两种加锁的方式获取SqlSession
public class SqlSessionFactoryUtil{
//sqlSessionFactory
private static SqlSessionFactory sqlSessionFactory = null;
//类线程锁
private static final Class CLASS_LOCK = SqlSessionFactoryUtil.class;
private SqlSessionFactoryUtil(){}
public static SqlSessionFactory initSqlSessionFactory(){
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try{
inputStream = Resource.getResourceAsStream(resource);
} catch(IOException ex){
Logger.getLogger(SqlSessionFactoryUtil.class.getName().log(Level.SERVER, null, ex));
}
synchronized(CLASS_LOCK){
if(sqlSessionFactory == null){
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
}
return sqlSessionFactory;
}
public static SqlSession openSqlSession(){
if(sqlSessionFactory == null)
initSqlSessionFactory();
return sqlSessionFactory.openSession();
}
}
另一种适合在多线程环境下的util写法
package com.unicorn.mybatishw.utils;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private MyBatisUtil(){
}
private static final String RESOURCE = "mybatis-config.xml";
private static SqlSessionFactory sqlSessionFactory = null;
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
static {
Reader reader = null;
try {
reader = Resources.getResourceAsReader(RESOURCE);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
sqlSessionFactory = builder.build(reader);
} catch (Exception e1) {
throw new ExceptionInInitializerError("初始化MyBatis错误,请检查配置文件或数据库");
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
public static SqlSession getSession(){
//sessionTL的get()方法根据当前线程返回其对应的线程内部变量,
//也就是我们需要的Session,多线程情况下共享数据库链接是不安全的。
//ThreadLocal保证了每个线程都有自己的Session。
SqlSession session = threadLocal.get();
// 如果session为null,则打开一个新的session
if (session == null){
session = (sqlSessionFactory !=null) ?sqlSessionFactory.openSession():null;
threadLocal.set(session);
}
return session;
}
public static void closeSession(){
SqlSession session = (SqlSession) threadLocal.get();
threadLocal.set(null);
if (session !=null){
session.close();
}
}
}
由于在多线程的环境下初始化单例,往往需要加线程锁避免对象多次初始化,也是为了高效利用数据库的资源
转载请注明出处,谢谢!
感谢杨开振先生所著的《深入浅出Mybatis技术原理与实战》,笔者博客的内容一部分是自己实战中的经验,另一部分是学习这本书籍内容的总结。