使用IDEA操作Maven專案+Mybatis框架的簡單方法(1)
(此篇只記錄連線資料庫部分內容)
菜鳥心得小記,大神請無視
首先建立Maven專案(建立過程在此不作贅述)
在pom.xml配置檔案中引入相關資源依賴
<!--新增依賴--> <dependencies> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.4</version> </dependency> <!--junit模組,方便測試程式碼--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--用來連線mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.41</version> </dependency> <!--記錄執行日誌,方便查詢錯誤,同時會看到一些有意思的執行過程--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
在src/main/resources目錄下建立三個配置檔案
log4j配置百度上到處都是,在此不作贅述
database.properties檔案配置如下圖所示
myconfig.xml配置如下
<?xml version="1.0" encoding="UTF-8"?> <!--表頭可直接使用--> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--配置標籤,新增database.properties進來,方便連線資料庫--> <properties resource="database.properties"></properties> <!--設定日誌實現方式為LOG4J--> <settings> <setting name="logImpl" value="LOG4J"/> </settings> <!--環境配置,default為設定預設呼叫的環境配置--> <environments default="dev"> <environment id="dev"> <!--事務管理方式為JDBC--> <transactionManager type="JDBC"></transactionManager> <!--資料來源從連線池獲取--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments> </configuration>
然後在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物件
程式碼無止境,日後繼續研究