(此篇只记录连接数据库部分内容)
菜鸟心得小记,大神请无视
首先创建Maven项目(创建过程在此不作赘述)
在pom.xml配置文件中引入相关资源依赖
org.mybatis
mybatis
3.4.4
junit
junit
4.12
mysql
mysql-connector-java
5.1.41
log4j
log4j
1.2.17
在src/main/resources目录下创建三个配置文件
log4j配置百度上到处都是,在此不作赘述
database.properties文件配置如下图所示
myconfig.xml配置如下
然后在src/main/java中创建MybatisUtil工具类
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 MybatisUtil {
//创建私有静态的引用,确保该引用只会建立一个且不能被外部直接修改
private static SqlSessionFactory sqlSessionFactory=null;
//使用静态代码块,以保证该部分代码在类加载的同时就能首先被加载
static {
try {
//以输入流的形式读取配置文件
InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
//将工厂类的引用指向由SqlSessionBuilder类对象调用build(配置输入流)方法创建的SqlSession工厂类对象
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession对象
public static SqlSession createSqlSession(){
return sqlSessionFactory.openSession();
}
//关闭sqlSession
public static void closeSqlSession(SqlSession sqlSession){
if(sqlSession!=null){
sqlSession.close();
}
}
}
此时我们可以在src/test/java目录下创建测试类测试连接
import com.bdqn.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class UserTest {
@Test
public void getConnTest(){
//调用MybatisUtil类的类方法创建sqlSession对象
SqlSession sqlSession=MybatisUtil.createSqlSession();
if(sqlSession!=null){
System.out.println("success");}
MybatisUtil.closeSqlSession(sqlSession); }}
如果此前的一切配置无误,则会在控台输出“success”
刚刚接触以上代码的时候我就有个疑问,回想IO流的相关内容,我们在MybatisUtil工具类创建了一个字节流,可是放眼通篇代码都没有将它关闭,这显然是不合理的,所以一定是在其后的某个环节调用某个方法时自动关闭了该流,可疑性最大的自然是sqlSession.close(),顾名思义,这个方法最像是在做一些关闭流的工作,接下来就是查看深层代码的过程了。
通过万能的ctrl+左键我们进入到了DefaultSqlSession类,看到了如下代码
public void close() {
try {
executor.close(isCommitOrRollbackRequired(false));
dirty = false;
} finally {
ErrorContext.instance().reset();
}}
继续深入executor.close()方法,来到了BaseExecutor类,看到如下代码
public void close(boolean forceRollback) {
try {
try {
rollback(forceRollback);
} finally {
if (transaction != null) transaction.close();
}
} catch (SQLException e) {
// Ignore. There's nothing that can be done at this point.
log.debug("Unexpected exception on closing transaction. Cause: " + e);
} finally {
transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
}
在这里我们看到了一个很熟悉的单词,transaction事务,继续深入close()方法,来到JdbcTransaction类
public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
connection.close();
}
}
此处的代码已经能看得很清楚了,重置了AutoCommit(Mysql事务自动提交属性),输出了关闭JDBC连接的相关日志信息,以及关闭了数据库连接,那么问题来了,IO流呢?此时我仍然认为是在之前查看的过程中忽略了什么,于是借助度娘查找到了一篇虽然没有解决我的问题但是同样让我受益匪浅的文章,一个由session.close()引发的血案(来自本站),解释了连接池方式连接数据库如果不调用sqlSession.close()方法会导致的可怕后果。
回到最开始的问题,其实可疑目标也只剩sqlSessionFactoryBuilder.build()和sqlSessionFactory.openSession()了,从前者开始继续深入方法,来到SqlSessionFactoryBuilder类,看到如下代码
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
谢天谢地!原来这么容易就能找到,我们的IO流刚刚传进来解析完成就被人家迫不及待地关上了。
与此同时也可以看出一些SqlSessionFactoryBuilder的原理,是将解析过的xml配置信息传入了DefaultSqlSessionFactory(Configuration configuration)参数里面,返回一个SqlSessionFactory对象
代码无止境,日后继续研究