![Java EE核心框架实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/215/729215/b_729215.jpg)
第1章 MyBatis 3操作数据库
本章将和大家一起分享MyBatis 3框架,此框架的主要作用就是更加便携地操作数据库,比如将数据库返回的内容进行List或实体类的封装,将执行操作的SQL语句配置到XML文件中,这样做有利于代码的后期维护,使代码的分层更加明确。MyBatis框架还具有优化查询效率的缓存等功能。那么在本章中,读者应该着重掌握如下内容:
· 使用基于Eclipse的MyBatis插件执行CURD增删改查操作;
· 使用MyBatis操作常用数据库Oracle、MySQL、MsSQL;
· MyBatis框架中核心对象的生命周期;
· MyBatis结合ThreadLocal类进行CURD的封装。
1.1 MyBatis介绍
为什么要使用MyBatis框架呢?举一个最简单的例子,在使用传统的JDBC代码时,需要写上必要的DAO层代码,在DAO层代码中将数据表中的数据封装到自定义的实体类中。这给代码的维护带来了问题。但MyBatis和Hibernate解决了这样的问题,使用它们做查询时,可以自动地将数据表中的数据记录封装到实体或Map中,再将它们放入List中返回。这么常见的功能都可以由MyBatis和Hibernate自由方便地实现,可见,使用这两个框架开发应用软件会非常方便快捷。
MyBatis是一个持久化框架,它有不同的语言版本,比如.NET和Java都有MyBatis对应的类库;它有大多数ORM框架都具有的功能,比如程序员自定义的SQL语句、调用存储过程和一些高级的映射。但在这里需要说明的是,它是一种半自动化的ORM映射框架,所以使用方式和Hibernate有非常大的区别。它以SQL语句为映射基础,在使用MyBatis框架时,可以将SQL语句灵活多变的特性融入项目开发中。
另外,如果使用MyBatis这个框架,还可以省略大多数的JDBC代码,因为它把常用的JDBC操作都进行了封装,可以加快开发效率。MyBatis可以使用XML或Annotations注解的方式将数据表中的记录映射成一个Map或Java POJO实体对象,这也是现在流行ORM的技术方向。比如Hibernate和大多数JPA规范实现者都可以使用Annotations注解的方式来设计程序。
由于MyBatis框架是第三方软件,因此必须单独进行下载,下载的网址为:
http://code.google.com/p/mybatis/
打开网页后看到如图1-1所示的界面。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0019_0001.jpg?sign=1738769777-apwg7kJ8I4tQHRcW2D7aMDzOCztK1fjU-0-1c1d4502836a8b0eb21309a335681931)
图1-1 MyBatis官方网站
继续操作,单击Downloads链接,打开如图1-2所示的界面。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0019_0002.jpg?sign=1738769777-lGR3f4xM1tYxLD85WDW0Qr6X0Uz4VceV-0-75eabdb3f07dc634a48f91b0506c0354)
图1-2 准备下载MyBatis框架
此刻已经把MyBatis框架从官网下载到本地计算机中,然后就可以使用它的jar文件进行开发了。下载的zip文件包含开发PDF文档及源代码和jar文件。
1.2 MyBatis操作数据库的步骤
开门见山永远是快速学习一门技术最好的方式。
MyBatis框架的核心是SqlSessionFactory对象,从SqlSessionFactory类的名称来看,它是创建SqlSession对象的工厂。但SqlSessionFactory对象的创建来自于SqlSessionFactoryBuilder类,也就是使用SqlSessionFactoryBuilder类创建SqlSessionFactory对象。
使用SqlSessionFactoryBuilder类创建SqlSessionFactory对象的方式可以来自于一个XML配置文件,也可以来自于一个实例化的Configuration对象。
1.2.1 使用XML配置文件创建SqlSessionFactory对象
使用XML配置文件方式创建SqlSessionFactory对象的核心代码如下。
package test; 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 Test { public static void main(String[] args) { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream); System.out.println(sqlSessionFactory); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
上述代码的主要作用就是取得SqlSessionFactory工厂对象。下面测试代码是否能正常创建SqlSessionFactory类的实例。
其中mybatis-config.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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name="url" value="jdbc:sqlserver://localhost:1079;databaseName=ghydb" /> <property name="username" value="sa" /> <property name="password" value="" /> </dataSource> </environment> </environments> </configuration>
配置文件mybatis-config.xml中主要定义的就是如何连接数据库,以及连接数据库所必备的username和password及url等参数。
项目结构如图1-3所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0021_0001.jpg?sign=1738769777-PkzHrXhydlbZp4yj7aMvNwRsVfT1XKTK-0-fb1245017a61722bfda7760af23b5d3c)
图1-3 项目结构
加入当时最新版的MyBatis框架的jar包,如图1-4所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0021_0002.jpg?sign=1738769777-gOClLd82vAoJKWAZedyBaO3iLAv8qcji-0-cf5db3368f5c711c961d2b33cc4f2e80)
图1-4 使用当前最新的MyBatis 3.2.2版本
运行程序后并没有出现异常,输出的信息如图1-5所示。
到此,SqlSessionFactory对象成功地从XML配置文件中创建。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0021_0003.jpg?sign=1738769777-svfIsuc9j961PhTnheUgHaVEL72bGHm3-0-1076b39ccdc5041f5baeb693c2fbeb7a)
图1-5 输出sqlSessionFactory对象
1.2.2 SqlSessionFactoryBuilder和SqlSessionFactory类的结构
SqlSessionFactoryBuilder类的结构如图1-6所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0021_0004.jpg?sign=1738769777-OLf36FuY8u2Ck7xsW98ymzr696J7PXZy-0-8a6b941586cb2b47f4a9b73b26f62022)
图1-6 SqlSessionFactoryBuilder类的结构
SqlSessionFactory类的结构如图1-7所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0022_0001.jpg?sign=1738769777-uir3g7Pkto8iBkrFWyGcOc3so8ysLf5s-0-b6c82e1d9b75f379bf530d8c53ebb069)
图1-7 SqlSessionFactory类的结构
从图1-6和图1-7中可以看到,两者的类结构中基本上全是重载的方法,主要是为了取得SqlSessionFactory和SqlSession对象。
1.2.3 使用MyBatis Generator工具逆向
在ORM框架MyBatis中,实现数据表与JavaBean映射时,配置的代码比较复杂,这种情况也存在于Hibernate框架中,虽然MyBatis框架实现ORM的原理是使用SQL语句进行映射JavaBean,但映射的代码还是比较繁多,所以为了加快开发效率,MyBatis官方提供一个Eclipse插件,该插件主要的功能就是生成ORM映射所需要的文件,但在目前来看,此插件只支持eclipse-java-indigo-SR2以上的版本,所以笔者在这里下载了eclipse-java-indigo-SR2-win32,在线成功安装了MyBatis Generator插件,下一步就是使用此插件生成ORM映射文件了。
新建一个Java项目,然后在Java项目的src节点上右键单击,新建一个MyBatis生成ORM文件的配置文件,如图1-8所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0022_0002.jpg?sign=1738769777-wIuQ7aMBhFttCNSdEPKkaO475KFsvBFh-0-a351027f4ed959f45b4666ed871dcb36)
图1-8 创建生成ORM的配置xml文件
单击Next按钮,出现如图1-9所示的界面。
在图1-9界面中,不需要更改配置,保持默认设置即可。单击Finish按钮完成配置文件的创建。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0023_0001.jpg?sign=1738769777-YNVJPf5SmcX4UBD1cvmzBacOLax0qLWn-0-48097d1b8713ab2a50ef22ba4014968a)
图1-9 将文件放入src路径下即可
对生成的generatorConfig.xml配置文件代码进行如下更改。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration> <context id="generatorJava"> <jdbcConnection driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver" connectionURL="jdbc:sqlserver://localhost:1079;databaseName=ghydb" userId="sa" password="" /> <javaModelGenerator targetPackage="orm" targetProject="generatorJava" /> <sqlMapGenerator targetPackage="orm" targetProject="generatorJava" /> <javaClientGenerator targetPackage="orm" targetProject="generatorJava" type="XMLMAPPER" /> <table schema="dbo" tableName="userinfo"> </table> </context> </generatorConfiguration>
配置文件generatorConfig.xml是MyBatis Generator插件中必备的文件,通过此文件可以从数据表的结构逆向出对应的Java类,然后用MyBatis的API就可以对这些Java类进行操作,从而演变成对数据表的增删改查操作。
数据表userinfo的表结构如图1-10所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0023_0002.jpg?sign=1738769777-e6FsGcEGnucAyp1sErdNNiKzDd8kmd9m-0-d5d3003931f6e43437b6d1ae98db03e9)
图1-10 userinfo数据表的结构
注意 需要在Java项目中添加sql驱动jar包。
准备就绪后,单击图1-11中的Generate My Batis/i BATIS Artifacts菜单。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0024_0001.jpg?sign=1738769777-EGSHKvvZYADpWszDPNqr95M9bIE30cU1-0-b33b2495502eda38fdb1db173d88118a)
图1-11 根据XML配置文件生成orm映射文件
成功生成orm映射文件后,项目结构如图1-12所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0024_0002.jpg?sign=1738769777-Fp5t7hTpIQnkF7ACi69AxAoPzSeiaImr-0-63be377274e2074607043c8346f4e1af)
图1-12 成功生成orm映射文件
把orm包中的内容复制到MyEclipse中Web项目的src路径中,如图1-13所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0024_0003.jpg?sign=1738769777-sAz4tquEiwaP3gzZl353RCkmeMtfWKTO-0-3c312e8536b867e99762385faa29f8ab)
图1-13 MyEclipse中Web项目的结构
在Web项目中添加MyBatis需要的jar文件。
至此,MyBatis的基础类文件已经准备完毕。
1.2.4 使用SqlSession对象在MsSql数据库中新建记录
本节开始把一条记录插入userinfo数据表中。
在Web项目的src目录中创建mybatis-config.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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name="url" value="jdbc:sqlserver://localhost:1079;databaseName=ghydb" /> <property name="username" value="sa" /> <property name="password" value="" /> </dataSource> </environment> </environments> <mappers> <mapper resource="orm/UserinfoMapper.xml" /> </mappers> </configuration>
Servlet核心代码如下。
package controller; import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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 orm.Userinfo; public class test extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Userinfo userinfo = new Userinfo(); userinfo.setUsername("usernameValue"); userinfo.setPassword("passwordValue"); String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream); SqlSession sqlSsession = sqlSessionFactory.openSession(); sqlSsession.insert("insert", userinfo); sqlSsession.commit(); sqlSsession.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Servlet中的代码实现一个经典的insert数据表的功能,从代码中可以看到MyBatis用最精简的API就可以完全控制数据表中的记录,可见不管从学习、开发等方面MyBatis的成本都比较低。
运行程序后,在控制台输出如下异常信息:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: 当IDENTITY_INSERT设置为OFF时,不能为表'userinfo'中的标识列插入显式值。
通过信息可以知道,MyBatis并没有识别userinfo数据表中主键id是自增的情况,解决办法很简单,回到eclipse,将generatorConfig.xml代码改成如下代码。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration> <context id="generatorJava"> <jdbcConnection driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver" connectionURL="jdbc:sqlserver://localhost:1079;databaseName=ghydb" userId="sa" password="" /> <javaModelGenerator targetPackage="orm" targetProject="generatorJava" /> <sqlMapGenerator targetPackage="orm" targetProject="generatorJava" /> <javaClientGenerator targetPackage="orm" targetProject="generatorJava" type="XMLMAPPER" /> <table schema="dbo" tableName="userinfo"> <generatedKey column="id" sqlStatement="sqlserver" identity="true" /> </table> </context> </generatorConfiguration>
这里添加了关键的配置代码:
<generatedKey column="id" sqlStatement="sqlserver" identity="true" />
定义主键值id是自增的。
将生成的orm包中所有内容再次复制到MyEclipse的Web项目中,再次运行Servlet,成功在数据表中添加了一条记录,如图1-14所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0026_0001.jpg?sign=1738769777-5XkIujx6ukG5oCndrKJwwc6KkXKjVOvR-0-532e8c19350dbffae34cc466c4d776e8)
图1-14 成功添加一条记录
1.2.5 使用SqlSession对象在Oracle数据库中新建记录
回到Eclipse,按照以下代码改动配置文件generatorConfig.xml的代码。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration> <context id="generatorJava"> <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@localhost:1522:accp11g" userId="ghy" password="123" /> <javaModelGenerator targetPackage="orm" targetProject="generatorJava" /> <sqlMapGenerator targetPackage="orm" targetProject="generatorJava" /> <javaClientGenerator targetPackage="orm" targetProject="generatorJava" type="XMLMAPPER" /> <table schema="ghy" tableName="userinfo"> <generatedKey column="id" sqlStatement="select idauto.nextval from dual" identity="false" /> </table> </context> </generatorConfiguration>、
关键配置是如下代码。
<generatedKey column="id" sqlStatement="select idauto.nextval from dual" identity="false" />
由于Oracle数据库使用序列来获取ID主键值,因此不配置上述代码在运行时会出现异常。
用Eclipse生成orm的映射文件,并复制到MyEclipse中的Web项目中,运行Servlet,在数据表中插入了新记录,并且id值由序列生成,结果如图1-15所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0027_0001.jpg?sign=1738769777-QhZceGw8D1OfZ7cwD3onBUeXASiO20U6-0-013de548a301a5dd1bbd54f648b30895)
图1-15 Oracle数据表中的新记录
1.3 使用MyBatis针对3种数据库(Oracle、MSSQL和MySQL)实现CURD
前面都是使用MyBatis Generator工具生成实体和SQL映射文件,并不能从基础上讲述MyBatis框架的使用,本节将从零基础开始研究如何使用MyBatis框架针对3种主流数据库实现经典功能CURD。
1.3.1 针对Oracle的CURD
MyBatis框架针对每一种数据库的操作都大同小异,本节将用示例演示3种主流数据库的CURD操作。
1.创建userinfo数据表
创建userinfo数据表,表结构如图1-16所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0028_0001.jpg?sign=1738769777-Yc4Ef0wsISkUZDCQubxQxMxQm9ucabTx-0-2c078bd7b949adaea025670b460a0e20)
图1-16 userinfo数据表的结构
2.从Eclipse产生逆向的实体类
在Eclipse中新建java项目,名称为oracleGenerator,添加MyBatis配置文件generator Config.xml,配置代码内容如下。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration> <context id="oracleGenerator"> <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@localhost:1522:accp11g" userId="ghy" password="123" /> <javaModelGenerator targetPackage="orm" targetProject="oracleGenerator" /> <sqlMapGenerator targetPackage="orm" targetProject="oracleGenerator" /> <javaClientGenerator targetPackage="orm" targetProject="oracleGenerator" type="XMLMAPPER" /> <table schema="ghy" tableName="userinfo"> <generatedKey column="id" sqlStatement="select idauto.nextval from dual" identity="false" /> </table> </context> </generatorConfiguration>
根据此配置文件会生成实体类Userinfo.java。
3.创建Web项目并配置基本开发环境
回到MyEclipse,创建一个Web项目,命名为mybatis_curd_oracle,将Eclipse项目oracle Generator中的orm包中的Userinfo.java复制到MyEclipse项目中的src路径下,如图1-17所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0029_0001.jpg?sign=1738769777-drtr3k1RTp3wU7XcAsKs4fJdK4MtrDoo-0-84b957f2f6d03787d7bf2e1640b2051b)
图1-17 MyEclipse中的orm包中有实体
实体类Userinfo.java的类结构如图1-18所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0029_0002.jpg?sign=1738769777-ZNME8jzWuYL15AeoTVVx6WlMOc6IVHnB-0-1392566b58a50f741f3759e8c9b51701)
图1-18 Userinfo.java的类结构
在Web项目mybatis_curd_oracle中的src路径下创建连接数据库的配置文件mybatis-config. xml,代码如下。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//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="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1522:accp11g" /> <property name="username" value="ghy" /> <property name="password" value="123" /> </dataSource> </environment> </environments> <mappers> <mapper resource="userinfoMapping.xml" /> </mappers> </configuration>
其中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="orm.Userinfo"> <selectKey resultType="java.lang.Long" keyProperty="id" order="BEFORE"> select idauto.nextval from dual </selectKey> insert into userinfo(id,username,password,age,insertDate) values(#{id},#{username},#{password},#{age},#{insertdate}) </insert> <select id="getUserinfoById" parameterType="int" resultType="orm.Userinfo"> select * from userinfo where id=#{id} </select> <delete id="deleteUserinfoById" parameterType="int"> delete from userinfo where id=#{id} </delete> <select id="getAllUserinfo" resultType="orm.Userinfo"> select * from userinfo </select> <update id="updateUserinfoById" parameterType="orm.Userinfo"> update userinfo set username=#{username},password=#{password},age=#{age},insertDate=#{insertdate} where id=#{id} </update> </mapper>
需要特别说明的是,如果SQL语句有一些特殊字段,则必须按照如下格式使用SQL语句。
<![CDATA[ sql语句 ]]>
其中配置代码如下所示。
<selectKey resultType="java.lang.Long" keyProperty="id" order="BEFORE"> select idauto.nextval from dual </selectKey>
主要的功能是根据序列对象生成一个主键id值,并且此值还可以从代码中获取,也就是插入一条记录后代码就可以获取刚才插入记录的id值。
属性parameterType定义参数的类型,属性resultType定义返回值的类型。
继续创建测试用的Servlet对象,完整的项目结构如图1-19所示。
在图1-19中可以发现src路径下两2个dtd文件,这样为了在开发xml配置或xml映射文件时实现代码自动提示功能。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0030_0001.jpg?sign=1738769777-voqbxAy4Bi8jiPYSRuPBLOXCeAdlBVjd-0-ef39157df8ad44a17b2a7d5aefa82c42)
图1-19 完整的项目结构
4.创建获取SqlSession对象的工具类
获取SqlSession对象的工具类的核心代码如下。
package dbtools; import java.io.IOException; import java.io.InputStream; 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 abstract class GetSqlSession { public static SqlSession getSqlSession() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream); SqlSession sqlSsession = sqlSessionFactory.openSession(); return sqlSsession; } }
5.插入多条记录
创建Servlet,核心代码如下。
public class insertUserinfo extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Userinfo userinfo = new Userinfo(); userinfo.setUsername("高洪岩"); userinfo.setPassword("岩洪高"); userinfo.setAge(100L); userinfo.setInsertdate(new Date()); SqlSession sqlSession = GetSqlSession.getSqlSession(); sqlSession.insert("mybatis.testcurd.insertUserinfo", userinfo); System.out.println(userinfo.getId()); sqlSession.commit(); sqlSession.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
变量sqlSession的insert方法的第一个参数是userinfoMapping.xml映射文件<insert>标签的id值,还要加上namespace命名空间的前缀,映射文件的部分代码如下。
<?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" ……>
在代码中可以看到获取已经插入数据表中记录的主键值。
执行Servlet后在控制台输出的结果如图1-20所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0031_0001.jpg?sign=1738769777-BB4hy4VNazR2w5OPaDnp2321AHnsQxC1-0-95eac66115296fc5f97efe1587c2f836)
图1-20 插入多条记录
Oracle数据库中userinfo数据表的内容如图1-21所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0031_0002.jpg?sign=1738769777-T8qMjSH5DrO1wxgq26PyOl4Uxlkk8GiZ-0-c20ba7613af0bb6d9c745ffb900b4277)
图1-21 出现3条数据记录
6.根据id值查询记录
创建Servlet,核心代码如下。
public class getUserinfoById extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { SqlSession sqlSession = GetSqlSession.getSqlSession(); Userinfo userinfo = sqlSession.selectOne( "mybatis.testcurd.getUserinfoById", 7); System.out.println(userinfo.getId()); System.out.println(userinfo.getUsername()); System.out.println(userinfo.getPassword()); System.out.println(userinfo.getAge()); System.out.println(userinfo.getInsertdate().toLocaleString()); sqlSession.commit(); sqlSession.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
程序运行后的结果如图1-22所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0032_0001.jpg?sign=1738769777-8dtCQqiqs9kZWbmsQheUh2kbLwNjJrAS-0-b28fef654a92843055fc33756d5ae088)
图1-22 输出id是7的信息
7.查询所有记录
创建Servlet,核心代码如下。
public class getAllUserinfo extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { SqlSession sqlSession = GetSqlSession.getSqlSession(); List<Userinfo> listUserinfo = sqlSession .selectList("mybatis.testcurd.getAllUserinfo"); for (int i = 0; i < listUserinfo.size(); i++) { Userinfo userinfo = listUserinfo.get(i); System.out.println(userinfo.getId() + " " + userinfo.getUsername() + " " + userinfo.getPassword() + " " + userinfo.getAge() + " " + userinfo.getInsertdate().toLocaleString()); } sqlSession.commit(); sqlSession.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
程序运行后输出3条记录,如图1-23所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0033_0001.jpg?sign=1738769777-A1YkkQuGlx5FTAIkSSvc8cCOL2WARtK8-0-3597b7cf43ee92104b3619f046547aa4)
图1-23 输出3条记录信息
8.更新记录
创建Servlet,核心代码如下。
public class updateUserinfoById extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { SqlSession sqlSession = GetSqlSession.getSqlSession(); Userinfo userinfo = sqlSession.selectOne( "mybatis.testcurd.getUserinfoById", 7); userinfo.setUsername("最新版高洪岩"); sqlSession.update("mybatis.testcurd.updateUserinfoById", userinfo); sqlSession.commit(); sqlSession.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
程序运行后数据表userinfo中的记录已更新,如图1-24所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0033_0002.jpg?sign=1738769777-iQ2yg4K86KT0HPLMtWvTceP9Sw8TSebD-0-f8469b5794c2d8b650ce6dfeeca16584)
图1-24 userinfo数据表中内容已更新
9.删除记录
创建Servlet,核心代码如下。
public class deleteUserinfoById extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { SqlSession sqlSession = GetSqlSession.getSqlSession(); sqlSession.delete("mybatis.testcurd.deleteUserinfoById", 6); sqlSession.commit(); sqlSession.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
程序运行后,将id为6的记录删除了,如图1-25所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0034_0001.jpg?sign=1738769777-XT0Wh6eQ5mZq7WCc4GPs3zhXcJxwhVJJ-0-adf9e7f927a4d02df892956a634b3a7b)
图1-25 无id为6的记录
到此,针对Oracle数据库的CURD操作到此结束。
1.3.2 针对MSSQL的CURD
操作MSSQL数据库和操作Oracle数据库的大体步骤相同,在SQL Server数据库中创建数据表,如图1-26所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0034_0002.jpg?sign=1738769777-2kZKlZKB6yw54NogtBKJGU4fnLbPRXnu-0-52bc6fe770b7691da6e7f28a89c1e346)
图1-26 数据表的结构
1.使用Eclipse逆向实体类
用相同的方法在Eclipse中创建Java项目,命名为mssqlGenerator,添加MyBatis生成文件,配置内容如下。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration> <context id="mssqlGenerator"> <jdbcConnection driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver" connectionURL="jdbc:sqlserver://localhost:1079;databaseName=ghydb" userId="sa" password="" /> <javaModelGenerator targetPackage="orm" targetProject="mssqlGenerator" /> <sqlMapGenerator targetPackage="orm" targetProject="mssqlGenerator" /> <javaClientGenerator targetPackage="orm" targetProject="mssqlGenerator" type="XMLMAPPER" /> <table schema="dbo" tableName="userinfo"> <generatedKey column="id" sqlStatement="sqlserver" identity="true" /> </table> </context> </generatorConfiguration>
关键代码如下。
<generatedKey column="id" sqlStatement="sqlserver" identity="true" />
它的作用是定义userinfo数据表中的id字段是自增的,不需要显式地设置值。
2.创建Web项目并搭建基本的开发环境
在MyEclipse中创建Web项目,复制Userinfo.java到Web项目中,并且创建一个连接数据库的配置文件mybatis-config.xml,代码如下。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//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="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name="url" value="jdbc:sqlserver://localhost:1079;databaseName=ghydb" /> <property name="username" value="sa" /> <property name="password" value="" /> </dataSource> </environment> </environments> <mappers> <mapper resource="userinfoMapping.xml" /> </mappers> </configuration>
还要创建sql映射文件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="orm.Userinfo" useGeneratedKeys="true" keyProperty="id"> insert into userinfo(username,password,age,insertDate) values(#{username},#{password},#{age},#{insertdate}) </insert> <select id="getUserinfoById" parameterType="int" resultType="orm.Userinfo"> select * from userinfo where id=#{id} </select> <delete id="deleteUserinfoById" parameterType="int"> delete from userinfo where id=#{id} </delete> <select id="getAllUserinfo" resultType="orm.Userinfo"> select * from userinfo </select> <update id="updateUserinfoById" parameterType="orm.Userinfo"> update userinfo set username=#{username},password=#{password},age=#{age},insertDate=#{insertdate} where id=#{id} </update> </mapper>
3.添加记录并且返回主键值
创建Servlet对象,插入记录的代码和Oracle数据库对应的Servlet代码一致,运行后在控制台输出3条记录的主键ID值,结果如图1-27所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0036_0001.jpg?sign=1738769777-ZeWNy8WeaJEb325jFwmcQWJEgppedhfe-0-8ca4fb73d146443bfb631d452c3b5196)
图1-27 向mssql数据库中插入3条记录
数据表userinfo中的内容如图1-28所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0036_0002.jpg?sign=1738769777-idS91ICmigDUjKEsIdtDIEIvHMT0i07l-0-fd05c9318c692891067b421f36338953)
图1-28 userinfo数据表中的内容
4.其他业务方法的测试
其他业务方法的代码和操作Oracle数据库的大体一致,并且已经成功运行,具体的代码请参见本书中的源代码。
1.3.3 针对MySQL的CURD
在MySQL数据库中创建数据表userinfo,表结构如图1-29所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0037_0001.jpg?sign=1738769777-QXwlkozYMdgBLXMTAnlldox51nsT2LDs-0-73c714a140efd78878e942dd3db0b177)
图1-29 userinfo数据表的结构
一定要勾选Auto Increment复选框,以使字段id值实现自增的效果。
1.使用Eclipse逆向实体类
在Eclipse中创建Java项目,添加逆向配置文件generatorConfig.xml,代码如下。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration> <context id="mysqlGenerator"> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3307/ghydb" userId="root" password="123" /> <javaModelGenerator targetPackage="orm" targetProject="mysqlGenerator" /> <sqlMapGenerator targetPackage="orm" targetProject="mysqlGenerator" /> <javaClientGenerator targetPackage="orm" targetProject="mysqlGenerator" type="XMLMAPPER" /> <table schema="ghydb" tableName="userinfo"> <generatedKey column="id" sqlStatement="mysql" identity="true" /> </table> </context> </generatorConfiguration>
2.创建Web项目并搭建基本的开发环境
在MyEclipse中创建Web项目,命名为mybatis_curd_mysql,复制Userinfo.java实体类,并且创建一个连接数据库的配置文件mybatis-config.xml,代码如下。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//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="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3307/ghydb" /> <property name="username" value="root" /> <property name="password" value="123" /> </dataSource> </environment> </environments> <mappers> <mapper resource="userinfoMapping.xml" /> </mappers> </configuration>
还要创建SQL映射文件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="orm.Userinfo" useGeneratedKeys="true" keyProperty="id"> insert into userinfo(username,password,age,insertDate) values(#{username},#{password},#{age},#{insertdate}) </insert> <select id="getUserinfoById" parameterType="int" resultType="orm.Userinfo"> select * from userinfo where id=#{id} </select> <delete id="deleteUserinfoById" parameterType="int"> delete from userinfo where id=#{id} </delete> <select id="getAllUserinfo" resultType="orm.Userinfo"> select * from userinfo </select> <update id="updateUserinfoById" parameterType="orm.Userinfo"> update userinfo set username=#{username},password=#{password},age=#{age},insertDate=#{insertdate} where id=#{id} </update> </mapper>
MySQL和MSSQL数据库生成主键的映射代码一致。
3.添加记录并且返回主键值
创建Servlet对象,插入记录的代码和Oracle数据库对应的Servlet代码一致,运行后在控制台输出3条记录的主键ID值,结果如图1-30所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0039_0001.jpg?sign=1738769777-SATSEmMEzXzuWwZRhTksVAtjFI9RW4lq-0-931fb078cc4a9866d440b35a15b58c26)
图1-30 向mysql数据库中插入4条记录
数据表userinfo中的内容如图1-31所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0039_0002.jpg?sign=1738769777-mTUvxfxVIPFNgHp7iGFvwDoNplyUsKLd-0-78ed9ebd76cbae3b15e298876532c98f)
图1-31 数据表userinfo中的4条记录
4.其他业务方法的测试
其他业务方法的代码和操作Oracle数据库的大体一致,并且已经成功运行,具体的代码请参见本书中的源代码。
1.4 MyBatis核心对象的生命周期与封装
在前面对3种数据库实现基本的CURD后,读者应该了解了MyBatis核心对象的使用,本节将会继续介绍这些核心对象的生命周期。
对象的生命周期也就是对象从创建到销毁的过程,但在此过程中,如果实现的代码质量不佳,那么很容易造成程序上的错误或效率的降低。
(1)SqlSessionFactoryBuilder对象可以被JVM虚拟机所实例化、使用或者销毁。一旦使用SqlSessionFactoryBuilder对象创建SqlSessionFactory后,SqlSessionFactoryBuilder类就不需要存在了,也就是,不需要保持此对象的状态,可以随意地任由JVM销毁。因此SqlSession FactoryBuilder对象的最佳使用范围是方法之内,也就是说,可以在方法内部声明SqlSessionFactoryBuilder对象来创建SqlSessionFactory对象。
(2)SqlSessionFactory对象由SqlSessionFactoryBuilder对象创建。一旦创建SqlSessionFactory类的实例,该实例应该在应用程序执行期间都存在,根本不需要每一次操作数据库时都重新创建它,所以应用它的最佳方式就是写一个单例模式,或使用Spring框架来实现单例模式对SqlSessionFactory对象进行有效的管理。
(3)SqlSession对象由SqlSessionFactory类创建,需要注意的是,每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享,它也是线程不安全的,所以千万不要在Servlet中声明该对象的一个实例变量。因为Servlet是单例的,声明成实例变量会造成线程安全问题,也绝不能将SqlSession实例的对象放在一个类的静态字段甚至是实例字段中,还不可以将SqlSession实例的对象放在任何类型的管理范围中,比如Servlet对象中的HttpSession会话。在接收到HTTP请求时,可以打开一个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) { 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 sql, Map valueMap) { SqlSession sqlSession = GetSqlSession.getSqlSession(); return sqlSession.insert(sql, valueMap); } public int delete(String sql, Map valueMap) { SqlSession sqlSession = GetSqlSession.getSqlSession(); return sqlSession.delete(sql, valueMap); } public int update(String sql, Map valueMap) { SqlSession sqlSession = GetSqlSession.getSqlSession(); return sqlSession.update(sql, valueMap); } public List<Map> select(String sql, Map valueMap) { SqlSession sqlSession = GetSqlSession.getSqlSession(); return sqlSession.selectList(sql, 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 into userinfo(username,password,age,insertDate) values(#{username},#{password},#{age},#{insertdate}) </insert> <select id="getUserinfoById" parameterType="map" resultType="map"> select * from userinfo where id=#{id} </select> <delete id="deleteUserinfoById" parameterType="map"> delete from userinfo where id=#{id} </delete> <select id="getAllUserinfo" resultType="map"> select * from userinfo </select> <update id="updateUserinfoById" parameterType="map"> update userinfo set username=#{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 configuration PUBLIC "-//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="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name="url" value="jdbc:sqlserver://localhost:1079;databaseName=ghydb" /> <property name="username" value="sa" /> <property name="password" value="" /> </dataSource> </environment> </environments> <mappers> <mapper resource="userinfoMapping.xml" /> </mappers> </configuration>
1.4.6 创建名为test的Servlet对象
该对象的主要作用就是测试在一个请求中多次获取的SqlSession对象是不是同一个,核心代码如下。
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-32所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0044_0001.jpg?sign=1738769777-ZvcGszrU4U1W2VzCObMPczsHvtgzCOfd-0-2abfba1374c8d536f16d3b3ecb1f3bc2)
图1-32 获得的SqlSession对象是同一个
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-33所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0045_0001.jpg?sign=1738769777-MwMoo2xxoXJ3biVfNPwEvamFPZ1Is1yl-0-d7844310a40fcb4cc780e529f492ec3b)
图1-33 控制台输出的信息
数据表中的数据如图1-34所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0045_0002.jpg?sign=1738769777-UEITrlcobnXG2LooW43mwen4WRnWafzm-0-4d5d10980c2c315a49c40ba32632d533)
图1-34 成功添加两条记录
上面的步骤证明添加多条记录成功,userinfo数据表中有两条记录。再来测试异常回滚的情况,更改部分的代码如下。
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数据表中是否还存在两条记录呢?查看userinfo数据表,其内容如图1-35所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0046_0001.jpg?sign=1738769777-Em5VyATMaBgz0BrgkVP0FHbmBfzypreB-0-0adf2d6df627ae3470a8c61dc6c237a6)
图1-35 成功回滚后还是两条记录
在userinfo数据表中多添增几条记录,便于后面的测试,新增的记录如图1-36所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0046_0002.jpg?sign=1738769777-XM1ZbPKK3Lwe9iOtPQhSGzio9nvsN3fY-0-3149d03c4c08fc14e3b2411b869484e2)
图1-36 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-37所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0047_0001.jpg?sign=1738769777-8zCHx2M3xVJYo6coizYfh7VORz6snF89-0-996ae8545f5dfe8308f1c7a9e4064bec)
图1-37 成功删除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-38所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0048_0001.jpg?sign=1738769777-6xb97hqdtY0ZfOi2McDjJSEI9FcEUDag-0-c300239eff015dcd9b3944359b94bfa8)
图1-38 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<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-39所示的结果。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0048_0002.jpg?sign=1738769777-Fx3EtFIowjJMLljU2F0BiWxvkeVtdQbW-0-c25a00b3cfab2becddf077e91899406f)
图1-39 控制台输出的信息
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-40所示。
![](https://epubservercos.yuewen.com/193A2B/3731471403551601/epubprivate/OEBPS/Images/figure_0049_0001.jpg?sign=1738769777-g4DloxvT2ktrj0T7nUTcuGP3gPIzRXER-0-cd1b01647a3f8ee5d59f5ab1e8def1d1)
图1-40 控制台输出的多条记录信息
ORM框架MyBatis介绍到这里,读者应该能熟练地使用它进行数据库的CURD操作,并且对核心API在使用上有一个了解。