首頁>技術>

在前面對2種主流資料庫實現基本的CURD後,對MyBatis核心物件在使用上應該不再陌生,在本中將會繼續介紹一下這些核心物件的生命週期。

物件的生命週期也就是物件從建立到銷燬的過程,但在此過程中,如果實現的程式碼品質不太優質,那麼很容易造成程式上的錯誤或效率的降低。

SqlSessionFactoryBuilder物件可以被JVM虛擬機器所例項化、使用或者銷燬。一旦你使用

SqlSessionFactoryBuilder物件建立了SqlSessionFactory後,SqlSessionFactoryBuilder類就不需要存在了,也就是不需要保持此物件的狀態,可以隨意的任由JVM銷燬,因此SqlSessionFactoryBuilder物件的最佳使用範圍是方法之內,也就是說可以在方法內部宣告SqlSessionFactoryBuilder物件來建立SqlSessionFactory物件。

SqlSessionFactory物件是由SqlSessionFactoryBuilder物件建立而來。一旦SqlSessionFactory類的例項被建立,該例項應該在應用程式執行期間都存在,根本不需要在每一次操作資料庫時都重新建立它所以應用它的最佳方式就是寫一個單例模式,或使用Spring框架來實現單例模式對SqlSessionFactory物件進行有效的管理

SqlSession物件是由SqlSessionFactory類建立,需要注意的是,每個執行緒都應該有它自己的SqlSession例項。SqlSession的例項不能共享使用,因為它是執行緒不安全的,所以千萬不要在Servlet中宣告該物件的1個例項變數。因為Servlet是單例的,宣告成例項變數會造成執行緒安全問題,也絕不能將SqlSession物件放在一個類的靜態欄位甚至是例項欄位中,還不可以將SqlSession物件放在HttpSession會話或ServletContext上下文中。在接收到HTTP請求時,可以打開了1個SqlSession物件操作資料庫,然後返回響應,就可以關閉它了。關閉SqlSession很重要,你應該確保使用finally塊來關閉它,下面的示例就是一個確保SqlSession物件正常關閉的基本模式程式碼。

public class insertUserinfo extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {SqlSession sqlSession = GetSqlSession.getSqlSession();try {// sqlSession curd code sqlSession.commit();} catch (Exception e) {sqlSession.rollback();e.printStackTrace();} finally {sqlSession.close();}}}
1.4.1 建立GetSqlSessionFactory.java類

根據前面學習過的生命週期的知識,在後面的章節將對MyBatis核心程式碼進行封裝,這樣更有助於對資料CURD的方便性,建立Web專案,名稱為mybatis_threadlocal。

建立GetSqlSessionFactory.java類,完整程式碼如下。

package dbtools;import java.io.IOException;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;public class GetSqlSessionFactory {private static SqlSessionFactory sqlSessionFactory;private GetSqlSessionFactory() {}synchronized public static SqlSessionFactory getSqlSessionFactory() {try {if (sqlSessionFactory == null) {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} else {}} catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace();}return sqlSessionFactory;}}

在GetSqlSessionFactory.java類中使用單例設計模式來取得SqlSessionFactory物件。

1.4.2建立GetSqlSession.java類

建立GetSqlSession.java類的核心程式碼如下。

package dbtools;import org.apache.ibatis.session.SqlSession;public class GetSqlSession {private static ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();public static SqlSession getSqlSession() {SqlSession sqlSession = tl.get();if (sqlSession == null) {sqlSession = GetSqlSessionFactory.getSqlSessionFactory().openSession();tl.set(sqlSession);} else {}System.out.println("獲得的sqlSession物件的hashCode:" + sqlSession.hashCode());return sqlSession;}public static void commit() {if (tl.get() != null) {tl.get().commit();tl.get().close();tl.set(null);System.out.println("提交了");}}public static void rollback() {if (tl.get() != null) {tl.get().rollback();tl.get().close();tl.set(null);System.out.println("回滾了");}}}
1.4.3 建立DBOperate.java類

建立DBOperate.java類核心程式碼如下。

package dbtools;import java.util.List;import java.util.Map;import org.apache.ibatis.session.SqlSession;public class DBOperate {public int insert(String sqlId, Map valueMap) {SqlSession sqlSession = GetSqlSession.getSqlSession();return sqlSession.insert(sqlId, valueMap);}public int delete(String sqlId, Map valueMap) {SqlSession sqlSession = GetSqlSession.getSqlSession();return sqlSession.delete(sqlId, valueMap);}public int update(String sqlId, Map valueMap) {SqlSession sqlSession = GetSqlSession.getSqlSession();return sqlSession.update(sqlId, valueMap);}public List<Map> select(String sqlId, Map valueMap) {SqlSession sqlSession = GetSqlSession.getSqlSession();return sqlSession.selectList(sqlId, valueMap);}}

所有CURD的引數值都用Map物件進行封裝,所以看一下SQL對映檔案中的程式碼吧。

1.4.4 建立userinfoMapping.xml對映檔案

建立userinfoMapping.xml對映檔案的程式碼如下。

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd"> <mapper namespace="mybatis.testcurd"><insert id="insertUserinfo" parameterType="map" useGeneratedKeys="true" keyProperty="id">insert intouserinfo(username,password,age,insertDate)values(#{username},#{password},#{age},#{insertdate})</insert><select id="getUserinfoById" parameterType="map" resultType="map">select * fromuserinfo where id=#{id} </select><delete id="deleteUserinfoById" parameterType="map">delete fromuserinfo where id=#{id} </delete><select id="getAllUserinfo" resultType="map">select * from userinfo</select><update id="updateUserinfoById" parameterType="map">update userinfosetusername=#{username},password=#{password},age=#{age},insertDate=#{insertdate} where id=#{id} </update></mapper>
1.4.5 建立連線資料庫mybatis-config.xml配置檔案

建立連線資料庫的mybatis-config.xml配置檔案,程式碼如下。

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="自定義的值" /> <property name="url" value="自定義的值" /> <property name="username" value="自定義的值" /> <property name="password" value="自定義的值" /> </dataSource> </environment> </environments> <mappers> <mapper resource="userinfoMapping.xml" /> </mappers> </configuration>
1.4.6建立名稱為test的Servlet物件

該物件的主要作用就是測試在1個請求中多次獲取SqlSession物件是不是1個,核心程式碼如下。

public class test extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {GetSqlSession.getSqlSession();GetSqlSession.getSqlSession();GetSqlSession.getSqlSession();GetSqlSession.getSqlSession();GetSqlSession.getSqlSession();}}

程式執行後,在控制檯輸出資訊如圖1-35所示。

1.4.7新增記錄及異常回滾的測試

新增記錄及異常回滾的測試,核心程式碼如下。

public class insert extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {HashMap valueMap1 = new HashMap();valueMap1.put("username", "高洪巖今天1");valueMap1.put("password", "高洪巖明天1");valueMap1.put("age", 100);valueMap1.put("insertdate", new Date());HashMap valueMap2 = new HashMap();valueMap2.put("username", "高洪巖今天2");valueMap2.put("password", "高洪巖明天2");valueMap2.put("age", 100);valueMap2.put("insertdate", new Date());DBOperate dbo = new DBOperate();dbo.insert("insertUserinfo", valueMap1);dbo.insert("insertUserinfo", valueMap2);} catch (Exception e) {e.printStackTrace();GetSqlSession.rollback();} finally {GetSqlSession.commit();}}}

程式執行後,在控制檯輸出資訊如圖1-36所示。

資料表中的資料如圖1-37所示。

上面的步驟證明新增多條記錄成功,userinfo資料表中有2條記錄。

再來測試異常回滾的情況,更改部分程式碼如下。

HashMap valueMap2 = new HashMap();valueMap2.put("username","高洪巖今天2_123456789_123456789_123456789_123456789_123456789");valueMap2.put("password", "高洪巖明天2");valueMap2.put("age", 100);valueMap2.put("insertdate", new Date());程式執行後在控制檯輸出異常資訊如下。獲得的sqlSession物件的hashCode:24442607 獲得的sqlSession物件的hashCode:24442607 org.apache.ibatis.exceptions.PersistenceException:### Error updating database. Cause: com.microsoft.sqlserver.jdbc.SQLServerException: 將截斷字串或二進位制資料。### The error may involve mybatis.testcurd.insertUserinfo-Inline### The error occurred while setting parameters### SQL: insert into userinfo(username,password,age,insertDate) values(?,?,?,?)### Cause: com.microsoft.sqlserver.jdbc.SQLServerException: 將截斷字串或二進位制資料。at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:147)at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:134)at dbtools.DBOperate.insert(DBOperate.java:12)at controller.insert.doGet(insert.java:36) at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)rotocol.java:624)at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:445)at java.lang.Thread.run(Thread.java:619)Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: 將截斷字串或二進位制資料。at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:145) ... 17 more回滾了

通過上面的資訊可以得知,程式出現異常,並且已經回滾,那userinfo資料表中是否還是2條記錄呢?檢視一下,其內容如圖1-38所示。

public class delete extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {HashMap valueMap1 = new HashMap();valueMap1.put("id", 44);DBOperate dbo = new DBOperate();dbo.delete("deleteUserinfoById", valueMap1);} catch (Exception e) {e.printStackTrace();GetSqlSession.rollback();} finally {GetSqlSession.commit();}}}

程式執行後,userinfo資料表中的記錄如圖1-40所示。

1.4.9 更改記錄

更改記錄的核心程式碼如下。

public class update extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {HashMap valueMap1 = new HashMap();valueMap1.put("id", 45);valueMap1.put("username", "高洪巖今天3new");valueMap1.put("password", "高洪巖明天3new");valueMap1.put("age", 100);valueMap1.put("insertdate", new Date());DBOperate dbo = new DBOperate();dbo.update("updateUserinfoById", valueMap1);} catch (Exception e) {e.printStackTrace();GetSqlSession.rollback();} finally {GetSqlSession.commit();}}}

程式執行後,userinfo表中的資料如圖1-41所示。

1.4.10 查詢單條記錄

查詢單條記錄的核心程式碼如下。

public class getUserinfoById extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {HashMap valueMap1 = new HashMap();valueMap1.put("id", 39);DBOperate dbo = new DBOperate();List<Map> list = dbo.select("getUserinfoById", valueMap1);for (int i = 0; i < list.size(); i++) {Map rowMap = list.get(i);System.out.println(rowMap.get("id") + "_" + rowMap.get("username") + "_" + rowMap.get("password")+ "_" + rowMap.get("age") + "_" + rowMap.get("insertDate"));}} catch (Exception e) {e.printStackTrace();GetSqlSession.rollback();} finally {GetSqlSession.commit();}}}

程式執行後,在控制檯輸出如圖1-42所示的結果。

1.4.11 查詢多條記錄

查詢多條記錄的核心程式碼如下。

public class getAllUserinfo extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {DBOperate dbo = new DBOperate();List<Map> list = dbo.select("getAllUserinfo", null);for (int i = 0; i < list.size(); i++) {Map rowMap = list.get(i);System.out.println(rowMap.get("id") + "_" + rowMap.get("username") + "_" + rowMap.get("password")+ "_" + rowMap.get("age") + "_" + rowMap.get("insertDate"));}} catch (Exception e) {e.printStackTrace();GetSqlSession.rollback();} finally {GetSqlSession.commit();}}}

程式執行後,控制檯的輸出如圖1-43所示。

ORM框架MyBatis介紹到這裡,讀者應該能熟練地使用它進行資料庫的CURD操作,並且對核心API在使用上有一個了解。

本文節選自《Java EE核心框架實戰(第2版)》

本書基於MyBatis3+Hibernate5+Struts2+Spring4MVC+Spring4,融合了作者多年軟體開發和培訓的經驗,面向實戰,通過豐富且有參考價值的案例,展現了JavaEE開發領域中最核心、最實用的開發技術,幫助讀者全面提升開發技能。

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 一篇文章整合基於Flask應用Graphql上傳檔案的方法