4、传统Dao开发与MyBatis的Mapper动态代理开发
1、MyBatis介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
2、MyBatis架构
1、mybatis配置的sqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在sqlMapConfig.xml中加载。
2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
3、MyBatis简单入门实例
1)基本开发环境搭建:基于maven搭建MyBatis开发环境,然后进行测试数据库创建以及相关jar包的引入
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency>2)创建配置文件:根据架构图,首先创建sqlMapConfig.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> <properties resource="jdbc.properties"/> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> </configuration>这里我们使用了jdbc.properties将数据库的相关信息单独提取出来
3)创建pojo:与数据库中的表进行匹配,这里以user表举例
import java.io.Serializable; import java.util.Date; public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } }4)创建映射文件并集中到sqlMapConfig.xml:为User.java创建映射文件User.xml,该文件中主要进行SQL语句的编写
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 写Sql语句 --> <mapper namespace="user"> <select id="findUserById" parameterType="Integer" resultType="com.panlei.pojo.User"> select * from user where id = #{v} </select> </mapper>这里的不同的声明用不同的id进行区别,parameterType是传参的类型,resultType是返回值类型,要与后面讲到的方法调用进行匹配。namespace是为了区分不同的映射mapper文件集中到sqlMapConfig.xml中可能id冲突的问题,后面还会具体讲解。
5)具体测试1:根据id查询用户信息,还是创建SqlSessionFactory,然后获取SqlSession,再调用selectOne(..)方法,根据传递的"user.findUserById"定位到具体的映射文件的具体sql语句,这里传递的参数便是前面定义的所需参数
import com.panlei.pojo.User; 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 org.junit.Test; import java.io.IOException; import java.io.InputStream; public class TestMyBatis { @Test public void test1() { try { String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); User o = sqlSession.selectOne("user.findUserById", 10); System.out.println(o); } catch (IOException e) { e.printStackTrace(); } } }6)具体测试2:根据用户名模糊匹配查询
具体的sql语句格式:select * from user where username like '%五%'
这里传递的参数就是String类型,然后返回值可能是一个用户列表,这里用的是${value},不是前面的#{},后面具体讲解区别
<select id="findUserByUsername" parameterType="String" resultType="com.panlei.pojo.User"> select * from user where username like '%${value}%' </select>// 根据用户名模糊匹配 @Test public void test2() { try { String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> users = sqlSession.selectList("user.findUserByUsername", "五"); for(User u:users) { System.out.println(u); } } catch (IOException e) { e.printStackTrace(); } }7)#{}与${}的区别
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
8)具体实例3:添加用户,这里直接传递的参数是自定义的User对象实例,直接进行映射,其属性要与pojo中的属性名一致
<!-- 保存用户 --> <insert id="saveUser" parameterType="com.panlei.pojo.User"> INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert>这里在实际应用中可能需要立即获取新添加用户的id来进行后续操作,下面演示如何编码:
<insert id="saveUser" parameterType="com.panlei.pojo.User"> <!-- selectKey 标签实现主键返回 --> <!-- keyColumn:主键对应的表中的哪一列 --> <!-- keyProperty:主键对应的pojo中的哪一个属性 --> <!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql --> <!-- resultType:设置返回的id的类型 --> <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert>LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
然后在测试代码中可以直接打印插入用户的id,发现是最新的自增id。不需要额外的代码。
Mybatis解决jdbc编程的问题
1、数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。
2、Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
4、传统Dao开发与MyBatis的Mapper动态代理开发
传统的Dao开发,就是创建Dao,然后创建Dao的实现类,然后在Service中使用即可,还是需要针对具体的pojo,创建具体的mapper.xml文件。具体实现就不再详述。
MyBatis中官方推荐使用编写Mapper接口(相当于Dao接口),然后交给Mybatis进行处理,根据该接口自动创建该接口的动态代理对象。为实现这一目标,事先定义了Mapper接口的开发规范:
1.Mapper.xml文件中的namespace与mapper接口的类路径相同;
2.Mapper接口方法名和Mapper.xml中定义的每个statement的id相同;
3.Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;
4.Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
下面结合具体实例解释上述规范:
这样我们在具体执行时,会自动生成接口的代理类对象,然后执行接口的具体方法时,会根据规范找到对应mapper文件下的相应方法
package com.panlei.mybatisdemo; import com.panlei.mapper.UserMapper; import com.panlei.pojo.User; 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 org.junit.Before; import org.junit.Test; import java.io.InputStream; import java.util.Date; public class TestMapper { private SqlSessionFactory sqlSessionFactory; @Before public void init() throws Exception { // 创建SqlSessionFactoryBuilder SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 加载SqlMapConfig.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml"); // 创建SqlsessionFactory this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); } @Test public void testSaveUser() { // 获取sqlSession,和spring整合后由spring管理 SqlSession sqlSession = this.sqlSessionFactory.openSession(); // 从sqlSession中获取Mapper接口的代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setUsername("萨其马"); user.setSex("2"); user.setBirthday(new Date()); user.setAddress("北京"); // 执行查询方法 userMapper.saveUser(user); // 相当于 sqlSession.insert("namespace.saveUser", user) // System.out.println(user); sqlSession.commit(); // 和spring整合后由spring管理 sqlSession.close(); } }关于selectOne还是selectList
动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
5、sqlMapConfig.xml配置文件
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
1) properties(属性)
可以引用java属性文件中的配置信息,比如前面用到的jdbc.properties
2) typeAliases(类型别名)
我们前面在传递参数,设置类型的时候,都是使用的 包名+类名,这样比较费劲,那么能不能像配置基本数据类型或者String一样来进行配置呢?答案是可以的,需要利用类型别名。
<typeAliases> <!-- 单个别名定义 --> <typeAlias alias="user" type="com.panlei.pojo.User" /> <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) --> <package name="com.panlei.pojo" /> </typeAliases>在sqlMapConfig.xml中利用<typeAliases>的<typeAlias>进行单个别名的定义。当有特别多的类需要定义的时候,一个一个的定义同样很繁琐,这就可以利用<package>来进行统一的配置。
3) mappers(映射器)
<mapper resource=" " />
使用相对于类路径的资源(现在的使用方式),如:<mapper resource="sqlmap/User.xml" />
<mapper class=" " />
使用mapper接口类路径,如:<mapper class="com.panlei.mybatis.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<package name=""/>
注册指定包下的所有mapper接口,如:<package name="com.panlei.mybatis.mapper"/>。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
6、输入映射和输出映射
6.1 parameterType(输入类型)
在配置文件的编写具体语句时,我们需要传入一些参数,前面的例子,我们已经使用了简单的类型,例如Integer,还有自己定义的POJO的类型,比如我们自定义的User类型。
还有另外一种情况,就是自定义的类型中有另一个自定义类型的属性,比如User中有一个自定义Order类型的属性,这时我们需要传递POJO包装对象。下面以一个例子来具体讲解:
1)根据用户名模糊查询用户信息,这里虚设一个只有一个User属性的包装类,然后传递该包装类,利用其User属性的username模糊查询用户信息
包装类
在UserMapper.java中编写查询接口方法:
在UserMapper.xml中编写具体的数据库查询代码,注意四条对应规则(namespace,id,传参,返回类型):这里我们看到传递参数的名称并未使用,而是直接使用了TestUser中的user属性中的username属性
编写测试代码:
6.2 resultType(输出类型)
1)输出简单类型
测试例子:SELECT COUNT(*) FROM ‘user’
先是在UserMapper接口中定义查询方法
然后在UserMapper.xml文件中具体编写查询语句
测试输出
2)此外还可以输出POJO对象以及POJO的对象列表,这我们前面已经使用了,不再详述
6.3 resultMap(输出映射)
resultType可以指定将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
下面我们以具体的例子演示:
1) 查询order表的所有数据
order表的字段及数据如下:这里的user_id不为空
然后我们定义相应的POJO类型,这里我们将表中的user_id定义为userId属性,模拟字段与属性不一致的情况。
为更好的演示,我们第一次查询仍然使用resultType,看一下运行结果,然后再使用resultMap
具体的步骤仍然是创建OrderMapper接口,定义查询方法,然后在OrderMapper.xml中编写具体的查询语句,并设置resultType类型
最终查询结果输出如下:可以看到userId为null
上面的结果产生原因就是因为字段与属性没有一一对应的原因。下面我们使用resultMap进行演示:
只需要修改OrderMapper.xml即可,为其添加<resultMap>,然后在具体的语句中利用resultMap属性进行关联即可,注意里面的各个属性的含义。
这里因为只需要进行user_id与userId的映射,所以其他属性可以不用处理。
然后我们运行测试,发现userId已经有值了。
7、动态sql
通过mybatis提供的各种标签方法实现动态拼接sql。
7.1 if 标签
需求:根据性别和名字查询用户,有时候条件可能为空,需要进行判断,为空就不再作为条件
<select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` WHERE 1=1 <if test="sex != null and sex != ''"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </select>
7.2 where 标签
上面的sql还有where 1=1 这样的语句,很麻烦
可以使用where标签进行改造
<select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` <!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字,也就是删除 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select>
7.3 sql片段
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
把上面例子中的id, username, birthday, sex, address提取出来,作为sql片段,如下:
<!-- 声明sql片段 --> <sql id="userFields"> id, username, birthday, sex, address </sql> <select id="queryUserByWhere" parameterType="user" resultType="user"> <!-- SELECT id, username, birthday, sex, address FROM `user` --> <!-- 使用include标签加载sql片段;refid是sql片段id --> SELECT <include refid="userFields" /> FROM `user` <!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select>如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace
<select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT <include refid="com.panlei.mapper.OrderMapper.userFields" /> FROM `user` <!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select>
7.4 foreach标签
向sql传递数组或List,mybatis使用foreach解析,如下:
根据多个id查询用户信息
查询sql:
SELECT * FROM user WHERE id IN (1,10,24)
对上面用到包装类添加一个 List<Integer> ids 属性
UserMapper.xml如下
<!-- 根据ids查询用户 --> <select id="queryUserByIds" parameterType="queryVo" resultType="user"> SELECT * FROM `user` <where> <!-- foreach标签,进行遍历 --> <!-- collection:遍历的集合,这里是QueryVo的ids属性 --> <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 --> <!-- open:在前面添加的sql片段 --> <!-- close:在结尾处添加的sql片段 --> <!-- separator:指定遍历的元素之间使用的分隔符 --> <foreach collection="ids" item="item" open="id IN (" close=")" separator=","> #{item} </foreach> </where> </select>测试代码如下:
@Test public void testQueryUserByIds() { // mybatis和spring整合,整合之后,交给spring管理 SqlSession sqlSession = this.sqlSessionFactory.openSession(); // 创建Mapper接口的动态代理对象,整合之后,交给spring管理 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 使用userMapper执行根据条件查询用户 QueryVo queryVo = new QueryVo(); List<Integer> ids = new ArrayList<>(); ids.add(1); ids.add(10); ids.add(24); queryVo.setIds(ids); List<User> list = userMapper.queryUserByIds(queryVo); for (User u : list) { System.out.println(u); } // mybatis和spring整合,整合之后,交给spring管理 sqlSession.close(); }
8、关联查询
8.1 一对一查询
需求:查询所有订单信息,关联查询下单用户信息。
sql语句:
SELECT o.id, o.user_id userId, o.number, o.createtime, u.username, u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id
方法一:使用resultType
这里我们,继承Order类编写Order2User类作为新的pojo类,此pojo类中新增加了订单信息和用户信息。这样返回对象的时候,mybatis自动把用户信息也注入进来了。
使用OrderMapper接口,并在OrderMapper.xml中添加对应的查询语句,最后测试。
这里我们在sql语句中对数据库字段的uer_id使用了别名userId,这样就不需要使用resultMap来进行映射了。
方法二:使用resultMap
这里直接对Oeder.java进行修改,添加一个User属性,然后在OrderMapper.xml中建立对应的映射。
8.2 一对多查询
需求:查询所有用户信息及用户关联的订单信息
sql语句:
SELECT u.id, u.username, u.birthday, u.sex, u.address, o.id oid, o.number, o.createtime, o.note FROM `user` u LEFT JOIN `order` o ON u.id = o.user_id
这里类似于上面的方法二。修改User类,在UserMapper.xml的配置文件中添加<resultMap>,然后编写相应查询语句,最后测试。
9、MyBatis整合Spring
9.1 整合思路
1、SqlSessionFactory对象应该放到spring容器中作为单例存在;
2、传统dao的开发方式中,应该从spring容器中获得sqlsession对象;
3、Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象;
4、数据库的连接以及数据库连接池事务管理都交给spring容器来完成。
9.2 整合所需的jar包
Spring相关jar包:
Spring<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.1.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jms --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-messaging --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>5.1.4.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.1.4.RELEASE</version> </dependency>MyBatis相关jar包:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency>Spring+mybatis的整合包:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency>Mysql的数据库驱动jar包:
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency>数据库连接池的jar包:
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency>
9.3 创建配置文件
1) applicationContext.xml
View Code<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 引入JDBC配置文件 --> <context:property-placeholder location="jdbc.properties"/> <!-- 配置数据库连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 配置数据源 --> <property name="dataSource" ref="dataSource"/> <!-- 配置mybatis核心配置文件 --> <property name="configLocation" value="sqlMapConfig.xml"/> </bean> </beans>2) sqlMapConfig.xml
View Code<?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> <!-- 设置别名 --> <typeAliases> <!-- 2. 指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,大小写不敏感 --> <package name="com.panlei.pojo" /> </typeAliases> </configuration>3) jdbc.properties
View Codejdbc.driverClass=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost/webuser?serverTimezone=GMT%2B8 jdbc.user=root jdbc.password=panlei
4) log4j.properties
View Code# Global logging configuration log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
9.4 创建pojo
9.5 Dao开发方式简单使用
这里的内容前面有所涉及,本次只讲解关键的内容。
Dao接口与实现类具体代码不再展示,注意一点,在dao实现类中因为需要调用对应mapper.xml中的具体sql语句,也就需要SqlSession对象,因为我们是MyBatis与Spring整合,所以我们不需要自己去new一个对象了,前面我们已经在applicationContext.xml中对 SqlSessionFactoryBean 进行了配置,而且在spring与mybaits整合的jar包中对这种必然会使用的操作抽象为一个类:SqlSessionDaoSupport,我们需要在具体的Dao实现类中继承该类,然后使用其中的方法即可,具体如下图:
还有就是编写对应的mapper.xml文件,并在sqlMapConfig.xml中加载该文件,最后在applicationContext.xml配置Dao
然后运行测试
9.6 Mapper代理形式
这一部分的基础知识在第4节也有讲解,本次也只是讲解重要的部分或者没有涉及的部分。
首先还是UserMapper接口与UserMapper.xml按规则对应,然后还是讲解一下applicationContext.xml中的配置。
第一种方式是为每一个Mapper接口配置一个<bean>
用到的MapperFactoryBean也是属于mybatis-spring整合jar包
运行测试
第二种方式是用扫描包的形式配置。第一种方式需要为每一个mapper配置一个<bean>,当数量太多时,显得太麻烦。这里可以不注入SqlSessionFactoryBean,可以自动注入