在前面对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 tl = new ThreadLocal();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 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" ?> insert intouserinfo(username,password,age,insertDate)values(#{username},#{password},#{age},#{insertdate})select * fromuserinfo where id=#{id} delete fromuserinfo where id=#{id} select * from userinfoupdate userinfosetusername=#{username},password=#{password},age=#{age},insertDate=#{insertdate} where id=#{id}
1.4.5 创建连接数据库mybatis-config.xml配置文件
创建连接数据库的mybatis-config.xml配置文件,代码如下。
<?xml version="1.0" encoding="UTF-8" ?> -//mybatis.org//DTD Config 3.0//EN""mybatis-3-config.dtd">
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-35 获得的sqlSession对象是1个
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-36 控制台输出信息
数据表中的数据如图1-37所示。
图1-37 成功添加2条记录
上面的步骤证明添加多条记录成功,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所示。
图1-38 userinfo表中的多条记录
1.4.8 删除记录
删除记录的核心代码如下。
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-40 成功删除id为44的记录
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-41 userinfo表中的记录
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 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-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 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所示。
图1-43控制台输出多条记录信息
ORM框架MyBatis介绍到这里,读者应该能熟练地使用它进行数据库的CURD操作,并且对核心API在使用上有一个了解。