高级参数映射和返回值映射(重点)
a. Pojo包装pojo的参数映射
b. 当结果集列名与pojo属性名不一致的返回值映射
动态sql(重点)
关联查询结果(重点)
a. 一对一关联结果
b. 一对多关联结果
Mybatis整合spring
逆向工程
事前代码准备
今天学习内容的练习主要以MyBatis动态代理的方式访问编写访问数据库的代码,因此参照昨天的工程重新创建一个新工程作为今天代码练习的集成,同时需要把一些动态代理需要的目录、空文件提前构建好,以方便后面使用。
工程代码结构(UTF8)
{width=”1.7951388888888888in”
height=”0.3173611111111111in”}{width=”1.7951388888888888in”
height=”0.3173611111111111in”}{width=”3.09375in”
height=”1.8125in”}
Mapper映射文件及对应的接口文件
OrderMapper.xml
<?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“>
<!– 订单业务映射文件 –>
<mapper namespace=“cn.itcast.dao.OrderMapper”>
<!– SQL –>
</mapper>
OrderMapper.java
package cn.itcast.dao;
public interface OrderMapper {
}
UserMapper.xml
<?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“>
<!– 用户业务映射文件 –>
<mapper namespace=“cn.itcast.dao.UserMapper”>
<!– SQL –>
</mapper>
UserMapper.java
package cn.itcast.dao;
public interface UserMapper {
}
POJO定义
将昨天工程中的【User.java】拷贝到pojo的包下
把【资料\03.pojo\Order.java】拷贝到pojo的包下。
配置文件和属性文件
把昨天工程中Source
Folder【config】下的全部配置文件和属性文件拷贝过来。走查一下配置文件,把没有必要的注释删除,需要修改的配置修改。
<?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=“dev”>
<!– 开发数据库环境的配置 –>
<environment id=“dev”>
<!– 事务管理的配置 –>
<transactionManager type=“JDBC”/>
<!– 数据源配置:driver, url, username, password –>
<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>
<!– 配置映射文件 –>
<mappers>
<!– 通过包扫描DAO接口的方式批量加载映射文件 –>
<package name=“cn.itcast.dao”/>
</mappers>
</configuration>
测试类
package mybatis2;
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;
import org.junit.Before;
import org.junit.Test;
public class MyTest {
private SqlSessionFactory sqlSessionFactory;
// 测试初始化函数
@Before
public void init() throws Exception {
// 读取配置文件
InputStream inputStream = Resources.getResourceAsStream(“MyBatisConfig.xml”);
// 根据主配置文件创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
// 测试通过接口加载与之对应的映射文件
@Test
public void test1() throws Exception {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
// 执行数据库操作
} catch(Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
sqlSession.close();
}
}
}
高级输入映射(重点)
综合查询
{width=”7.268055555555556in”
height=”4.477083333333334in”}
综合查询在实际业务需求中十分常见。综合查询页面往往是包含多种查询维度的条件,比如上面的截图就是淘宝的订单查询页面。我们看到查询订单的条件包括:订单基本信息、用户信息、售后信息。
如果持久层使用MyBatis,应该如何接收参数呢?
需求
查询:用户名是姓王的并且手机是135开头的,订单状态是【待发货】的订单信息。
【SQL语句】有订单又有用户,SQL应该是一个关联查询:
SELECT
o.orderId,
o.userId,
o.orderStatus,
o.goodsId,
o.createDateTime
FROM
order1 o,
user u
WHERE
u.name LIKE ‘王%’
AND u.mobile LIKE ‘135%’
AND o.orderStatus = ‘02’
AND o.userId = u.userId
定义综合查询条件用POJO
因为查询条件是多维度的,它既不属于用户也不属于订单,所以不能用User.java和Order.java,需要重新定义一个包含User和Order的新POJO。
通常我们把保存查询条件的pojo称为QueryVo.java,其实就是普通的java
bean。我们需要订单基本信息和用户信息作为条件进行查询,所以其中包括了用户信息和订单信息。
【QueryVo.java】
public class QueryVo {
// 用户信息
private User user;
// 订单信息
private Order order;
setter/getter。。。。。
}
上面需求中的SQL需要两方面条件,一方面是订单的,一方面是用户的,所以可以在QueryVo中定义一个Order对象用于保存订单的查询条件,再定义一个User对象用于保存用户的查询条件。这样不容易混乱也不容易出现名称相似的属性造成的不知道该用哪个。
注意:我们不要把user的属性和order的属性条件混合到一起定义,这样定义没有错,而且在参数映射时也简单了,但是会让Vo变得很混乱,分不清属性谁是谁的。
SQL映射文件
【OrderMapper.xml】
<?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“>
<!– 订单业务映射文件 –>
<mapper namespace=“cn.itcast.dao.OrderMapper”>
<!– SQL –>
<!– 根据QueryVo查询订单信息 –>
<select id=“findOrderByQueryVo” parameterType=“cn.itcast.pojo.QueryVo”
resultType=“cn.itcast.pojo.Order”>
SELECT
o.orderId,
o.userId,
o.orderStatus,
o.goodsId,
o.createDateTime
FROM
order1 o,
user u
WHERE
u.name LIKE #{user.name}
AND u.mobile LIKE #{user.mobile}
AND o.orderStatus = #{order.orderStatus}
AND o.userId = u.userId
</select>
</mapper>
定义接口
【OrderMapper.java】
package cn.itcast.dao;
import cn.itcast.pojo.QueryVo;
import cn.itcast.pojo.Order;
public interface OrderMapper {
// 根据综合查询条件查询订单信息
public Order findOrderByQueryVo(QueryVo vo) throws Exception;
}
客户端测试程序
【MyTest.java】
// 测试根据QueryVo查询订单信息
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
User user = new User();
Order order = new Order();
user.setName(“王%”);
user.setMobile(“135%”);
order.setOrderStatus(“02”);
QueryVo vo = new QueryVo();
vo.setOrder(order);
vo.setUser(user);
// 执行数据库操作
List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
System.out.println(orderList);
sqlSession.close();
}
<SQL映射规范>(需要掌握)
·参数映射规范(四)
传多个参数并且是POJO包装类型时,parameterType=“pojo包装pojo类型”,占位符中的变量名等于Vo的属性.属性.属性…,直到找到传参属性名为止。
高级输出映射(重点)
按照返回值映射的规范MyBatis可以将SQL结果集自动的生成指定类型的java对象,但是如果满足不了返回值映射的规范怎么办?简单点说就是结果集列名与pojo中的属性名不相等的时候我们怎么做返回值映射?
解决的办法:就是手动定义返回值映射。
需求
根据订单id查询数据库中order2表的订单信息。但order2表的最大问题就是字段名是以下划线分割的,这与Order的pojo中的属性名不一致。
手动定义返回值映射
定义返回值映射
【OrderMapper.xml】
<说明>(需要掌握)
项目 解释
<resultMap> 用于自定义返回值映射的规则,即自定义哪个列名对应哪个属性名。
id 返回值映射的唯一标识
type 返回值映射中java对象的类型
<result> 用于定义一个返回值映射规范的标签,一个<resultMap>可以包含多个<result>
column 返回值映射中的列名
property 返回值映射中的属性名
<id> 用于定义返回值映射中主键列名与字段名的映射关系。用法和<result>一模一样,只是增加可读性。
<SQL映射示例>
<!– 自定义返回值映射的规范 –>
<resultMap type=“cn.itcast.pojo.Order” id=“order2ResultMap”>
<id column=“order_id” property=“orderId”/>
<!– <result column=”order_id” property=”orderId”/> –>
<result column=“user_id” property=“userId”/>
<result column=“order_status” property=“orderStatus”/>
<result column=“goods_id” property=“goodsId”/>
<result column=“create_date_time” property=“createDateTime”/>
</resultMap>
自定义了规范,MyBatis就可以利用这个自定义规范进行返回值映射了。
SQL
【OrderMapper.xml】
<说明>(需要掌握)
项目 解释
resultMap 引用返回值映射的自定义规范
<SQL映射示例>
<!– 根据id查询order2表的订单信息 –>
<select id=“findOrder2ById” parameterType=“String” resultMap=“order2ResultMap”>
SELECT
order_id,
user_id,
order_status,
goods_id,
create_date_time
FROM
order2
WHERE
order_id = #{orderId}
</select>
接口
【OrderMapper.java】
// 根据id查询订单信息
public Order findOrder2ById(String orderId) throws Exception;
客户端测试程序
【MyTest.java】
// 测试根据id查询订单信息
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
// 执行数据库操作
Order orderInfo = orderMapper.findOrder2ById(“6d081184-433e-11e7-ab09-448a5b6dba5c”);
System.out.println(orderInfo);
sqlSession.close();
}
用SQL字段别名满足返回值映射规范
利用SQL的字段可以定义别名的功能,满足字段名与POJO属性名相同的要求。
SQL
【OrderMapper.xml】
<!– 根据id查询order2表的订单信息2 –>
<select id=“findOrder2ById2” parameterType=“String” resultType=“cn.itcast.pojo.Order”>
SELECT
order_id as orderId,
user_id as userId,
order_status as orderStatus,
goods_id as goodsId,
create_date_time as createDateTime
FROM
order2
WHERE
order_id = #{orderId}
</select>
接口
【OrderMapper.java】
// 根据id查询订单信息2
public Order findOrder2ById2(String orderId) throws Exception;
客户端测试程序
【MyTest.java】
// 测试根据id查询订单信息
@Test
public void test2() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
// 执行数据库操作
// Order orderInfo = orderMapper.findOrderById(“6d081184-433e-11e7-ab09-448a5b6dba5c”);
Order orderInfo = orderMapper.findOrder2ById2(“6d081184-433e-11e7-ab09-448a5b6dba5c”);
System.out.println(orderInfo);
sqlSession.close();
}
动态SQL(重点)
本章内容针对SQL映射,赋予SQL映射更加强大灵活的特性,让SQL映射更能适应复杂多变的参数请求。因此本节内容比较杂,内容也较多,但每块内容都相对独立,不难掌握。
动态SQL条件
{width=”7.268055555555556in” height=”2.95in”}
<if>标签
【OrderMapper.xml】
<说明>(需要掌握)
项目 解释
<if> 用于判断它包含的SQL语句是否需要添加。
test 判断的逻辑条件,and表示与,or表示或,逻辑判断为true是添加包含的SQL语句,false就忽略。
<SQL映射示例>
<!– 根据动态条件查询订单信息 –>
<select id=“findOrderByQueryVo2” parameterType=“cn.itcast.pojo.QueryVo”
resultType=“cn.itcast.pojo.Order”>
SELECT
o.orderId,
o.userId,
o.orderStatus,
o.goodsId,
o.createDateTime
FROM
order1 o,
user u
WHERE 1 = 1
<if test=“user.name != null and user.name != ””>
AND u.name LIKE #{user.name}
</if>
<if test=“user.mobile != null and user.mobile != ””>
AND u.mobile LIKE #{user.mobile}
</if>
<if test=“order.orderStatus != null and order.orderStatus != ””>
AND o.orderStatus = #{order.orderStatus}
</if>
and o.userId = u.userId
</select>
【OrderMapper.java】
// 根据动态查询条件查询订单信息
public List<Order> findOrderByQueryVo2(CustomQueryVo vo) throws Exception;
【MyTest.java】
// 测试根据动态查询条件查询订单信息
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
User user = new User();
Order order = new Order();
user.setName(“王%”);
user.setMobile(“135%”);
order.setOrderStatus(“02”);
QueryVo vo = new QueryVo();
vo.setOrder(order);
vo.setUser(user);
// 执行数据库操作
// List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
List<Order> orderList = orderMapper.findOrderByQueryVo2(vo);
System.out.println(orderList);
sqlSession.close();
}
if标签不仅仅用于动态条件,SQL中所有接收参数的部分都可以通过if判断决定是否要追加,比如udate更新中可以实现更新项目的动态更新:
<update id=“updateUser” parameterType=“cn.itcast.pojo.User”>
UPDATE user
SET
<if test=“name != null and name != ””>
name = #{name},
</if>
<if test=“mobile != null and mobile != ””>
mobile = #{mobile},
</if>
<if test=“sex != null and sex != ””>
sex = #{sex},
</if>
<if test=“age != null and age != ””>
age = #{age},
</if>
<if test=“address != null and address != ””>
address = #{address},
</if>
WHERE
userId = #{userId}
</update>
上面的示例是有缺陷的,这个等到后面的学习中会改进它,现在只是让大家看到if标签不仅仅应用于where条件。
完善动态SQL条件
<where>标签
【OrderMapper.xml】
<说明>(需要掌握)
项目 解释
<where> 用于构建完整where条件的标签,有了它就不需要写where关键字了
它还能够去掉第一个条件前面的and或or,因此**<where>**可以和**<if>**标签组合实现更完美的动态条件。
<SQL映射示例>
<!– 根据动态条件查询订单信息(改进) –>
<select id=“findOrderByQueryVo3” parameterType=“cn.itcast.pojo.QueryVo”
resultType=“cn.itcast.pojo.Order”>
SELECT
o.orderId,
o.userId,
o.orderStatus,
o.goodsId,
o.createDateTime
FROM
order1 o,
user u
<where>
<if test=“user.name != null and user.name != ””>
AND u.name LIKE #{user.name}
</if>
<if test=“user.mobile != null and user.mobile != ””>
AND u.mobile LIKE #{user.mobile}
</if>
<if test=“order.orderStatus != null and order.orderStatus != ””>
AND o.orderStatus = #{order.orderStatus}
</if>
and o.userId = u.userId
</where>
</select>
【OrderMapper.java】
// 根据动态查询条件查询订单信息(改进)
public List<Order> findOrderByQueryVo3(CustomQueryVo vo) throws Exception;
【MyTest.java】
// 测试根据动态查询条件查询订单信息
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
User user = new User();
Order order = new Order();
user.setName(“王%”);
user.setMobile(“135%”);
order.setOrderStatus(“02”);
QueryVo vo = new QueryVo();
vo.setOrder(order);
vo.setUser(user);
// 执行数据库操作
// List<Order> orderList = orderMapper.findOrderByQueryVo(vo);
// List<Order> orderList = orderMapper.findOrderByQueryVo2(vo);
List<Order> orderList = orderMapper.findOrderByQueryVo3(vo);
System.out.println(orderList);
sqlSession.close();
}
SQL代码片段的复用
定义可重用的SQL代码段
【OrderMapper.xml】把【findOrderByQueryVo2】和【findOrderByQueryVo3】中的条件提取出去:
<说明>(需要掌握)
项目 解释
<sql> 定义可共用SQL片段的标签。将可共用的SQL片段(可以包含其他动态标签)包含在<sql></sql>中间
id 这个共用SQL片段的唯一标识
<SQL映射示例>
<!– 订单信息的查询条件 –>
<sql id=“order_query_condition”>
<if test=“user.name != null and user.name != ””>
AND u.name LIKE #{user.name}
</if>
<if test=“user.mobile != null and user.mobile != ””>
AND u.mobile LIKE #{user.mobile}
</if>
<if test=“order.orderStatus != null and order.orderStatus != ””>
AND o.orderStatus = #{order.orderStatus}
</if>
</sql>
修改后的【findOrderByQueryVo2】和【findOrderByQueryVo3】
<说明>(需要掌握)
项目 解释
<include> 引用已经定义好的SQL片段
refid 引用的SQL片段的id
<SQL映射示例>
<!– 根据动态条件查询订单信息 –>
<select id=“findOrderByQueryVo2” parameterType=“cn.itcast.pojo.QueryVo”
resultType=“cn.itcast.pojo.Order”>
SELECT
o.orderId,
o.userId,
o.orderStatus,
o.goodsId,
o.createDateTime
FROM
order1 o,
user u
WHERE 1 = 1
<include refid=“order_query_conditions”/>
and o.userId = u.userId
</select>
<!– 根据动态条件查询订单信息(改进) –>
<select id=“findOrderByQueryVo3” parameterType=“cn.itcast.pojo.QueryVo”
resultType=“cn.itcast.pojo.Order”>
SELECT
o.orderId,
o.userId,
o.orderStatus,
o.goodsId,
o.createDateTime
FROM
order1 o,
user u
<where>
<include refid=“order_query_conditions”/>
and o.userId = u.userId
</where>
</select>
可以测试一下,结果仍然可以执行。
动态多值SQL条件:foreach
{width=”7.268055555555556in”
height=”1.8680555555555556in”}
上面的屏幕尺寸是可以多选的。对于同一个条件可以选择多个条件值的情况下如何处理?
处理in条件
比如根据多个订单状态查询订单信息,我们需要传递多个订单状态。我们可以在查询条件的pojo类QueryVo中添加一个List<String>类型的属性,也可以直接传递List<String>类型的java对象。
- 在QueryVo中定义List<String>类型的属性:
【QueryVo.java】
public class QueryVo {
。。。。。。。
// 订单状态列表
private List<String> orderStatusList;
。。。。。。。
/**
* @return the orderStatusList
*/
public List<String> getOrderStatusList() {
return orderStatusList;
}
/**
* @param orderStatusList the orderStatusList to set
*/
public void setOrderStatusList(List<String> orderStatusList) {
this.orderStatusList = orderStatusList;
}
}
【OrderMapper.xml】
<说明>(需要掌握)
项目 解释
<foreach> 在参数映射中,用于循环遍历集合类型的参数。
collection 表示要循环遍历的集合对象名称
item 每次遍历时使用的临时变量名称,在循环内部用占位符来引用
separator 每次循环之间的分隔符号
open 循环开始之前的SQL语句部分(可选)
close 循环结束之后的SQL语句部分(可选)
<SQL映射示例>
<!– 根据多个订单状态查询订单信息(Vo中包装List) –>
<select id=“findOrderByOrderStatus” parameterType=“cn.itcast.pojo.QueryVo”
resultType=“cn.itcast.pojo.Order”>
SELECT
orderId,userId,orderStatus,goodsId,createDateTime
FROM
order1
WHERE
<!– 不带open和close属性的形式 –>
orderStatus in (
<foreach collection=“orderStatusList” item=“orderStatus” separator=“,”>
#{orderStatus}
</foreach>
)
或者
<foreach collection=“orderStatusList” item=“orderStatus” separator=“,”
open=“orderStatus in (“ close=“)”>
#{orderStatus}
</foreach>
</select>
<SQL映射规范>(需要掌握)
·参数映射规范(五)——<foreach>标签专用
处理集合参数,如果参数是parameterType=“Pojo(包含List属性)”时,
<foreach>中collection必须是List属性的变量名称。
【OrderMapper.java】
// 根据多个订单状态查询订单信息(Vo包装List)
public List<Order> findOrderByOrderStatus(CustomQueryVo vo) throws Exception;
【MyTest.java】
// 根据多个订单状态查询订单信息(Vo包装List)
@Test
public void test1() throws Exception {
SqlSession sqlSession = null;
sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List<String> orderStatusList = new ArrayList<String>();
orderStatusList.add(“01”);
orderStatusList.add(“02”);
orderStatusList.add(“03”);
QueryVo vo = new QueryVo();
vo.setOrderStatusList(orderStatusList);
// 执行数据库操作
List<Order> orderList = orderMapper.findOrderByOrderStatus(vo);
System.out.println(orderList);
sqlSession.close();
}
- 直接传递List:
【OrderMapper.xml】
<!– 根据多个订单状态查询订单信息2(直接传递List) –>
<select id=“findOrderByOrderStatus2” parameterType=“java.util.List”
resultType=“cn.itcast.pojo.Order”>
SELECT
orderId,userId,orderStatus,goodsId,createDateTime
FROM
order1
WHERE
<foreach collection=“list” item=“orderStatus” separator=“,”
open=“orderStatus in (“ close=“)”>
#{orderStatus}
</foreach>
</select>
<SQL映射规范>(需要掌握)
·参数映射规范(六)——<foreach>标签专用
处理集合参数,如果参数是parameterType=“List”时,<foreach>中collection属性值必须是list(必须小写,不能变)
【OrderMapper.java】
// 根据多个订单状态查询订单信息2(直接传递List)
public List<Order> findOrderByOrderStatus2(List<String> statusList) throws Exception;
【MyTest.java】
// 根据多个订单状态查询订单信息1(Vo包装List)
@Test
public void test1() throws Exception {
SqlSession sqlSession = null;
sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List<String> orderStatusList = new ArrayList<String>();
orderStatusLis.add(“01”);
orderStatusLis.add(“02”);
orderStatusLis.add(“03”);
CustomQueryVo vo = new CustomQueryVo();
vo.setOrderStatusList(orderStatusLis);
// 执行数据库操作
// List<Order> orderList = orderMapper.findOrderByOrderStatus1(vo);
List<Order> orderList2 = orderMapper.findOrderByOrderStatus2(orderStatusLis);
System.out.println(orderList2);
sqlSession.close();
}
or条件
【OrderMapper.xml】
<!– 根据多个订单状态查询订单信息3(or条件) –>
<select id=“findOrderByOrderStatus3” parameterType=“java.util.List”
resultType=“cn.itcast.pojo.Order”>
SELECT
orderId,userId,orderStatus,goodsId,createDateTime
FROM
order1
WHERE
<foreach collection=“list” item=“orderStatus” separator=“or”>
orderStatus = #{orderStatus}
</foreach>
</select>
【OrderMapper.java】
// 根据多个订单状态查询订单信息3(or条件)
public List<Order> findOrderByOrderStatus3(List<String> statusList) throws Exception;
【MyTest.java】
// 根据多个订单状态查询订单信息
@Test
public void test1() throws Exception {
SqlSession sqlSession = null;
sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List<String> orderStatusList = new ArrayList<String>();
orderStatusLis.add(“01”);
orderStatusLis.add(“02”);
orderStatusLis.add(“03”);
CustomQueryVo vo = new CustomQueryVo();
vo.setOrderStatusList(orderStatusLis);
// 执行数据库操作
// List<Order> orderList = orderMapper.findOrderByOrderStatus1(vo);
// List<Order> orderList2 = orderMapper.findOrderByOrderStatus2(orderStatusLis);
List<Order> orderList3 = orderMapper.findOrderByOrderStatus3(orderStatusLis);
System.out.println(orderList3);
sqlSession.close();
}
小结
上面的动态标签: <if>, <where>, <sql>,
<foreach>无论你如何使用我们始终要记住一个宗旨:
保证动态形成的SQL语句的语法正确
只要你能包装SQL语法正确,
你就可以灵活的使用这些动态标签实现你自己的动态SQL。
关联查询结果(重点)
商品订单数据模型
注意:这里面两个表的关联都是由SQL控制的,跟MyBatis一点关系都没有,现在我们面临的问题就是怎样把具有关联关系的结果集通过结果集映射返回给Java程序。
一对一查询结果集
SQL语句
SELECT
o.orderId,
o.goodsId,
o.orderStatus,
u.name,
u.address,
u.mobile
FROM
order1 o,
user u
WHERE
o.userId = u.userId
AND o.orderId = ‘52076fa9-433e-11e7-ab09-448a5b6dba5c’
修改订单POJO
如果查询结果中包含用户信息,就需要在Order.java
pojo中增加User类型的属性,然后把用户信息保存在这个User属性中。
package cn.itcast.pojo;
/**
* 订单信息POJO
*
* @author Derek Sun
*
*/
public class Order {
private String orderId;
private Integer userId;
private String orderStatus;
private String goodsId;
private Date createDateTime;
private User user;
。。。。。。
}
在实际业务中可能不仅仅包含用户信息,还可能有订单对应的商品信息、物流信息等等。
由于查询结果中需要包含一个User类型的对象,这样的结果集结构比较复杂,因此需要我们手动定义返回值映射,这就需要ResultMap发挥作用的时候了。
需要在定义返回值映射时在ResultMap中定义一个User类型的对象,并把属于用户的查询结果映射给User对象的属性。
ResultMap中定义POJO对象
【OrderMapper.xml】
<说明>(需要掌握)
项目 解释
<association> 用于在ResultMap标签中定义POJO对象
property 定义的POJO对象名称(注意:名称不能随便命名,必须符合返回值映射规范)
javaType 定义的POJO对象的类型
<SQL映射示例>
<!– 一对一查询结果集的返回 –>
<!– 定义订单综合查询结果与自定义订单pojo属性之间的对应关系 –>
<resultMap type=“cn.itcast.pojo.Order” id=“orderResultMap1”>
<id column=“order_id” property=“orderId” />
<result column=“goods_id” property=“goodsId” />
<result column=“order_status” property=“orderStatus” />
<association property=“user” javaType=“cn.itcast.pojo.User”>
<result column=“name” property=“name”/>
<result column=“address” property=“address”/>
<result column=“mobile” property=“mobile”/>
</association>
</resultMap>
<!– 根据订单id查询订单综合信息(订单基本信息、所属用户信息…) –>
<select id=“findOrderAndUserByOrderId” parameterType=“string”
resultMap=“orderResultMap1”>
SELECT
o.orderId,
o.goodsId,
o.orderStatus,
u.name,
u.address,
u.mobile
FROM
order1 o,
user u
WHERE
o.userId = u.userId
AND o.orderId = #{id}
</select>
<SQL映射规范>(需要掌握)
·返回值映射规范(四)
在<resultMap>中用<association>定义POJO对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对一结果的映射)
定义接口
【OrderMapper.java】
// 根据订单id查询订单综合信息(订单基本信息、所属用户信息…)
public Order findOrderAndUserByOrderId(String orderId) throws Exception;
客户端测试程序
【MyTest.java】
// 测试根据订单id查询订单综合信息(订单基本信息、所属用户信息…)
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
Order order = orderMapper.findOrderAndUserByOrderId(“5f560c1e-433e-11e7-ab09-448a5b6dba5c”);
System.out.println(order);
sqlSession.close();
}
扩展
如果返回多条一对一的查询结果,该如何来做?
- SQL
SELECT
o.orderId,
o.orderStatus,
o.goodsId,
u.userId,
u.name,
u.address
FROM
order1 o,
user u
WHERE
o.userId = u.userId
AND o.orderStatus = ‘02’
- POJO
同【Order.java】
- 接口定义
// 根据订单状态查询订单综合信息(订单基本信息、所属用户信息…)
public List<Order> selectOrderAndUserByOrderStatus(String orderStatus) throws Exception;
- 映射文件
<!– 根据订单状态查询订单综合信息(订单基本信息、所属用户信息…) –>
<select id=“selectOrderAndUserByOrderStatus” parameterType=“String”
resultMap=“customOrderResultType”>
SELECT
o.orderId,
o.orderStatus,
o.goodsId,
u.userId,
u.name,
u.address
FROM
order1 o,
user u
WHERE
o.userId = u.userId
AND o.orderStatus = #{status}
</select>
- 客户端测试
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List<CustomOrder> orderList = orderMapper.selectOrderAndUserByOrderStatus(“02”);
System.out.println(orderList);
sqlSession.close();
}
执行结果:
{width=”6.8125in” height=”1.6979166666666667in”}
**总结:无论是单条还是多条一对一结果,<resultMap> +
<association>的组合都适用。association里面还可以再嵌套association。**
一对多查询结果集
SQL语句
SELECT
u.name,
u.address,
u.mobile,
o.order_id,
o.order_status,
o.goods_id
FROM
user u,
order2 o
WHERE
o.user_id = u.userId
AND u.userId = 1001
从SQL查询的结果集上看用户名和地址都是重复的,这个用户相关的订单信息是多条不同的,这样的结果集最终返回到java对象中应该是一个用户信息,其中包含一个关于这个用户的订单信息的List集合。
修改用户POJO
如果查询用户结果中包含多个订单信息,就需要在User.java
pojo中增加Order类型的List属性,然后把属于这个用户多条订单信息保存到List<Order>属性中。
package cn.itcast.pojo;
import java.util.List;
/**
* 用户信息POJO
*
* @author Derek Sun
*
*/
public class User {
private String name;
private int userId;
private String mobile;
private String sex;
private int age;
private String address;
// 用户订单信息列表
private List<Order> orderList;
。。。。。。。
}
在实际业务中可能不仅仅包含订单信息,还可能有用户信用度信息、用户消费额度信息、推荐商品信息列表等等。
由于查询结果中需要包含一个List<Order>类型的对象,这样的结果集结构比较复杂,因此需要我们手动定义返回值映射,这就需要ResultMap发挥作用的时候了。
需要在定义返回值映射时在ResultMap中定义一个List<Order>类型的对象,并把属于这个用户的订单查询结果映射给List<Order>对象。
ResultMap中定义List对象
【UserMapper.xml】
<说明>(需要掌握)
项目 解释
<collection> 用于在ResultMap标签中定义List类型的对象
property 定义的List类型的对象名称(注意:名称不能随便命名,必须符合返回值映射规范)
ofType List中泛型的类型,即List其中一个对象的类型
<SQL映射示例>
<!– 一对多查询结果集返回 –>
<!– 定义用户综合查询结果集与自定义用户pojo属性之间的对应关系 –>
<resultMap type=“cn.itcast.pojo.User” id=“userResultMap”>
<result column=“name” property=“name” />
<result column=“address” property=“address” />
<result column=“mobile” property=“mobile”/>
<collection property=“orderList” ofType=“cn.itcast.pojo.Order”>
<id column=“order_id” property=“orderId” />
<result column=“order_status” property=“orderStatus” />
<result column=“goods_id” property=“goodsId” />
</collection>
</resultMap>
<!– 根据用户id查询用户综合信息(用户基本信息, 用户订单信息….) –>
<select id=“findUserAndOrderByUserId” parameterType=“int” resultMap=“userResultMap”>
SELECT
u.name,
u.address,
u.mobile,
o.order_id,
o.order_status,
o.goods_id
FROM
user u,
order2 o
WHERE
o.user_id = u.userId
AND u.userId = #{id}
</select>
<SQL映射规范>(需要掌握)
·返回值映射规范(五)
在<resultMap>中用<collection>定义List对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对多结果的映射)
定义接口
【OrderMapper.java】
package cn.itcast.dao;
import cn.itcast.pojo.User;
public interface UserMapper {
// 根据用户id查询用户综合信息(用户基本信息, 用户订单信息….)
public User findUserAndOrderByUserId(Integer id) throws Exception;
}
客户端测试程序
【MyTest.java】
// 测试根据用户id查询用户综合信息(用户基本信息, 用户订单信息….)
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserAndOrderByUserId(1001);
sqlSession.close();
}
扩展
如果返回多条一对多的查询结果,该如何来做?(多条一对多也可以理解成多对多,实际上多对多最终都是转化成一对多来实现的。)
- SQL
SELECT
u.userId,
u.name,
u.mobile,
o.orderId,
o.orderStatus,
o.goodsId
FROM
user u,
order1 o
WHERE
u.userId = o.userId
AND u.name LIKE ‘王%’
- POJO
同【User.java】
- 接口定义
// 根据用户名模糊查询用户综合信息(用户基本信息, 用户订单信息….)
public List<User> selectUserAndOrderListByUserName(String userName) throws Exception;
- 映射文件
<!– 根据用户名模糊查询用户综合信息(用户基本信息, 用户订单信息….) –>
<select id=“selectUserAndOrderListByUserName” parameterType=“String”
resultMap=“userResultMap”>
SELECT
u.userId,
u.name,
u.mobile,
o.orderId,
o.orderStatus,
o.goodsId
FROM
user u,
order1 o
WHERE
u.userId = o.userId
AND u.name LIKE #{userName}
</select>
- 客户端测试
@Test
public void test1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的动态代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.selectUserAndOrderListByUserName(“王%”);
sqlSession.close();
}
执行结果:
{width=”7.268055555555556in”
height=”2.611111111111111in”}
**总结:无论是单条还是多条一对多结果,<resultMap> +
<collection>的组合都适用。collection里面还可以再嵌套collection,但是一般没有那么复杂的数据结构。**
输入输出映射小结(重点)
<SQL映射规范>(需要掌握)
·参数映射规范
1)传单个参数时,parameterType=“java简单类型”,占位符中的变量可以任意名称,但不能没有。
2)传单个参数时,parameterType=“java简单类型”,拼接符中的变量名必须是value,也不能没有。
3)传多个参数时,parameterType=“pojo类型”,占位符或拼接符的变量名必须等于pojo中的属性名。
4)传多个参数并且是POJO包装类型时,parameterType=“pojo包装pojo类型”,占位符中的变量名等于Vo的属性.属性.属性…,直到找到传参属性为止。
5)<foreach>标签专用——处理集合参数,如果参数是parameterType=“Pojo(包含List属性)”时,
<foreach>中collection必须是List属性的变量名称。
6)<foreach>标签专用——处理集合参数,如果参数是parameterType=“List”时,<foreach>中collection属性值必须是list(必须小写,不能变)。
·返回值映射规范
1)返回单值时,resultType=“java简单类型”,值直接返回给java程序。
2)返回单条记录时,resultType=“pojo类型”,结果集的列名必须等于pojo的属性名。
3)返回多条记录时,resultType=“集合的pojo泛型的类型”,结果集列名必须等于pojo泛型的属性名。
4)在<resultMap>中用<association>定义POJO对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对一结果的映射)
5)在<resultMap>中用<collection>定义List对象,property的值必须等于<resultMap>的type指定的POJO中的属性名。(一对多结果的映射)
Spring与Mybatis整合
框架的整合就是软件之间的集成,它很抽象,因此在做整合之前先想好思路。规划好思路然后按照思路一步一步的做就可以实现框架的整合。
SM整合思路
思路分析
SM整合是中后端框架的整合:
Spring框架作为一个优秀的容器级框架在系统整合中一直充当着业务控制中心的作用。是后端的核心。管理着系统中重要的资源、重要的核心类的对象、业务层对象以及持久层Dao对象。
MyBatis作为一个优秀的持久层框架,其优势当然是访问数据库的具体工作,所以交出对重要资源和核心类对象的控制权,专心做好对数据库访问的具体工作。
分析后得出下面的思路。
思路整理
- 控制层
框架:由Spring负责重要的资源、核心类对象、DAO对象的管理。
配置:ApplicationContext.xml
——properties属性文件的载入(可选,推荐)
——数据源以及连接池(必选)
——MyBatis会话工厂bean(必须)
——传统Dao实现类的bean(可选)
——MyBatis动态代理Dao的bean(可选)
——MyBatis动态代理Dao的包扫描
(批量加载bean)(可选,推荐)
- 持久层
框架:由MyBatis负责访问数据库的具体工作,即通过映射文件中的SQL进行数据库操作。
配置:MyBatisConfig.xml(配置文件名称随意,有的人叫SqlMapConfig.xml)
——自定义别名配置(可选,不推荐)
——传统DAO开发方式需要的映射文件配置(可选,看有没有传统DAO的情况而定。)
Jar包
Spring的jar包
如何从Spring官网取得jar包
1 访问:
http://projects.spring.io/spring-framework/
{width=”2.0769225721784776in”
height=”2.0962423447069116in”}
点击[Reference]进入后, 搜索[Distribution Zip Files]
{width=”2.884615048118985in”
height=”1.8034744094488189in”}
{width=”7.268055555555556in”
height=”1.4784722222222222in”}
下面的才是spring的jar包下载的页面,对应的url:http://repo.spring.io/release/org/springframework/spring/
{width=”3.4173906386701662in”
height=”3.2107010061242343in”}
{width=”2.923421916010499in”
height=”2.9551279527559053in”}
{width=”7.268055555555556in”
height=”3.047222222222222in”}
以下是取得的jar包
{width=”1.3653849518810148in”
height=”2.1097900262467193in”}
Mybatis的jar包
{width=”1.1730774278215224in”
height=”0.20143700787401575in”}
{width=”1.3205129046369204in”
height=”1.3650874890638671in”}
数据库驱动jar
{width=”1.8269225721784776in”
height=”0.19167760279965004in”}
SM集成的jar
Spring与MyBatis的集成需要借助这个集成jar包才能把MyBatis的会话工厂、DAO的对象注入到spring的容器中去,没有它我们完不成SM的整合。
Spring与Mybatis整合包的取得地址:
https://github.com/mybatis/spring/releases
{width=”4.907753718285214in”
height=”2.4782611548556432in”}
{width=”4.1501596675415575in”
height=”1.591304680664917in”}
以下是我们使用的sm整合jar包:
{width=”1.461111111111111in”
height=”0.19935804899387577in”}
SM整合的其他依赖jar
以下是sm整合的其他依赖包
{width=”1.461111111111111in”
height=”0.8086953193350831in”}
创建工程(UTF-8)、导入jar、创建配置文件
{width=”2.4in” height=”1.9181813210848644in”}
其中ApplicationContext.xml是空的,下面在具体添加内容,其他配置文件是之前的工程中拷贝过来的。
SM环境整合
规划要进行配置的内容
根据上面的思路可知我们今天的整合主要面对的是两个配置文件:
ApplicationContext.xml
MyBatisConfig.xml
因为只是SM整合,还不是一个完整的系统,我们没有太多的代码可写,只是测试一下我们前面写在映射文件中的SQL在整合环境下好不好用即可。
ApplicationContext.xml
Spring配置样本可以从官网取得:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#jdbc
从官网取得的文件:
<?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”
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“>
<bean id=”corporateEventDao” class=”com.example.JdbcCorporateEventDao”>
<property name=”dataSource” ref=”dataSource”/>
</bean>
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource” destroy-method=”close”>
<property name=”driverClassName” value=”${jdbc.driverClassName}”/>
<property name=”url” value=”${jdbc.url}”/>
<property name=”username” value=”${jdbc.username}”/>
<property name=”password” value=”${jdbc.password}”/>
</bean>
<context:property-placeholder location=”jdbc.properties”/>
</beans>
数据源及属性文件的配置
<!– 1 properties属性文件的载入 –>
<context:property-placeholder location=“jdbc.properties”/>
<!– 2 数据源以及连接池配置 –>
<bean id=“dataSource” class=“org.apache.commons.dbcp.BasicDataSource” destroy-method=“close”>
<property name=“driverClassName” value=“${jdbc.driver}”/>
<property name=“url” value=“${jdbc.url}”/>
<property name=“username” value=“${jdbc.username}”/>
<property name=“password” value=“${jdbc.password}”/>
</bean>
基本和官网获取到的一样,只是属性文件的key名稍作修改。
Mybatis会话工厂bean的配置
<说明>(需要掌握)
项目 解释
核心类 org.mybatis.spring.SqlSessionFactoryBean
configLocation 核心类重要属性名,用value加载MyBatis核心配置文件
dataSource 核心类重要属性名,用ref引用数据源的id
<配置>
<!– 3. 配置会话工厂 –>
<!– 配置会话工程 –>
<bean id=“sqlSessionFactory” class=“org.mybatis.spring.SqlSessionFactoryBean”>
<!– 加载MyBatis核心配置文件 –>
<property name=“configLocation” value=“MyBatisConfig.xml” />
<!– 引用数据源bean,注意使用ref,属性名不要写错 –>
<property name=“dataSource” ref=“dataSource” />
</bean>
将MyBatis的核心配置文件中的配置删除
删除属性文件配置、数据库环境配置,如果有传统DAO,则需保留传统DAO需要使用的这个映射文件。
<?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>
<!– 自定义java bean的别名定义 –>
<!– <typeAliases>
<typeAlias type=”cn.itcast.pojo.User” alias=”user”/>
</typeAliases> –>
<!– 配置映射文件 –>
<mappers>
<!– 方式一: 根据映射文件在类目录下的相对路径加载映射文件 –>
<mapper resource=“cn/itcast/mapper/UserMapper.xml” />
</mappers>
</configuration>
传统DAO实现类的bean
<说明>(需要掌握)
项目 解释
DAO实现类要继承的父类 org.mybatis.spring.support.SqlSessionDaoSupport
继承父类的作用 由父类统一管理SqlSession对象的打开、关闭,DAO实现类方法只关注业务。
sqlSessionFactory 父类需要的重要属性名,用ref引用会话工厂的id
<配置>
<!– 4. 配置传统DAO实现类的bean –>
<!– 配置DAO接口的实例化bean(使用DAO接口的实现类) –>
<bean id=“userDao” class=“cn.itcast.dao.UserDaoImpl”>
<!– 引用会话工厂bean,注意使用ref,属性名不要写错 –>
<property name=“sqlSessionFactory” ref=“sqlSessionFactory” />
</bean>
DAO接口【UserDao.java】
package cn.itcast.dao;
import cn.itcast.pojo.User;
public interface UserDao {
// 根据id查询用户信息
public User findUserById(Integer id) throws Exception;
}
DAO实现类【UserDaoImpl.java】
package cn.itcast.dao;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import cn.itcast.pojo.User;
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User findUserById(Integer id) throws Exception {
// DAO接口实现类的方法中通过方法getSqlSession来取得sqlSession对象。
SqlSession sqlSession = this.getSqlSession();
// 根据id查询
User userInfo = sqlSession.selectOne(“user.selectUserById”, id);
return userInfo;
}
}
这里面没有关闭sqlSession的代码,如果加上会报错,告诉你不需要关闭,由Spring会帮你做。
测试【MyTest.java】
package sm;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.dao.UserDaoImpl;
import cn.itcast.mapper2.OrderMapper;
import cn.itcast.pojo.Order;
import cn.itcast.pojo.User;
public class MyTest {
@Test
public void test1() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext(“ApplicationContext.xml”);
UserDao userDao = (UserDao)ac.getBean(“userDao”);
User userInfo = userDao.findUserById(1001);
System.out.println(userInfo);
}
}
MyBatis动态代理DAO的bean
<说明>(需要掌握)
项目 解释
核心类 org.mybatis.spring.mapper.MapperFactoryBean
核心类作用 这个核心类帮助我们动态代理指定的DAO接口,并加载对应的映射文件,所以二者要同名同目录
所以这种DAO加载方式只适用于MyBatis动态代理DAO开发方式。
mapperInterface 核心类重要属性,value的值表示需要动态代理的接口的完全限定名
sqlSessionFactory 核心类中也继承了org.mybatis.spring.support.SqlSessionDaoSupport,这个父类需要会话工厂对象,用ref引用会话工厂的id
<配置>
<!– 5. 配置MyBatis动态代理DAO的bean –>
<bean id=“orderDao” class=“org.mybatis.spring.mapper.MapperFactoryBean”>
<!– 设置需要代理的DAO接口 –>
<property name=“mapperInterface” value=“cn.itcast.mapper2.OrderMapper” />
<!— 因为MapperFactoryBean继承了SqlSessionDaoSupport,所以需要给它传递会话工程bean –>
<property name=“sqlSessionFactory” ref=“sqlSessionFactory” />
</bean>
DAO接口【OrderMapper.java】
package cn.itcast.mapper2;
import cn.itcast.pojo.Order;
public interface OrderMapper {
// 根据id查询订单信息2
public Order findOrder2ById2(String orderId) throws Exception;
}
测试【MyTest.java】
package sm;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.dao.UserDaoImpl;
import cn.itcast.mapper2.OrderMapper;
import cn.itcast.pojo.Order;
import cn.itcast.pojo.User;
public class MyTest {
@Test
public void test2() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext(“ApplicationContext.xml”);
OrderMapper orderMapper = (OrderMapper)ac.getBean(“orderDao”);
Order orderInfo = orderMapper.findOrder2ById2(“57528381-433e-11e7-ab09-448a5b6dba5c”);
System.out.println(orderInfo);
}
}
MyBatis动态代理DAO的包扫描
这是真正企业中DAO动态代理的配置方式(注意:要将第五个配置先注释掉,才能测试第六个配置)
<说明>
项目 解释
核心类 org.mybatis.spring.mapper.MapperScannerConfigurer
核心类作用 这个核心类帮助我们批量动态代理指定包路径下的接口,是上面的批量形式,所以二者要同名同目录。
所以这种DAO加载方式只适用于MyBatis动态代理DAO开发方式。
basePackage 核心类重要属性名,用value加载需要扫描的包路径,需要多个包时,中间用半角逗号隔开
·注意:因为是包扫描,所以无法指定具体的id,只需class即可。
程序中需要使用哪个DAO接口时,用DAO接口名字首字母小写作为它的id即可。若接口名字开头
字母有两个及以上字母是大写的(如:TOrderMapper),那么就直接用DAO接口名字作为id;
这个核心类不需要配置会话工厂,它会自动去找Spring容器中注册的会话工厂对象。
<!– 6. 配置MyBatis动态代理DAO的包扫描 –>
<bean class=“org.mybatis.spring.mapper.MapperScannerConfigurer”>
<property name=“basePackage” value=“cn.itcast.mapper2” />
</bean>
DAO接口【OrderMapper.java】同第五个配置。
测试【MyTest.java】
@Test
public void test3() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext(“ApplicationContext.xml”);
OrderMapper orderMapper = (OrderMapper)ac.getBean(“orderMapper”);
Order orderInfo = orderMapper.findOrderById2(“57528381-433e-11e7-ab09-448a5b6dba5c”);
System.out.println(orderInfo);
}
Mybatis逆向工程
能够帮助我们生成繁琐又没有技术含量的POJO的代码。
还能帮助我们生成单表的增删改查的SQL映射文件以及动态代理接口。
之所以能帮我们生成单表的增删改查的处理是因为单表的这些操作是跟业务无关的,而且它生成的这些SQL中的条件都是全条件的(即对全部字段都可以作为条件,根据传递的是哪些字段的条件动态的生成SQL。)
将逆向工程导入workspace
{width=”2.321428258967629in”
height=”1.7101837270341207in”}
逆向工程构成
1 一个配置文件:generatorConfig.xml
2 三个jar包:
MyBatis核心jar:mybatis-3.2.7.jar
逆向工程的jar:mybatis-generator-core-1.3.2.jar
数据库驱动:mysql-connector-java-5.1.28-bin.jar
3 一个main函数方法,直接执行可以上传代码
以上内容均不需要我们记住里面的内容,就把整个工程看作一个工具,是官方提供给我们的工具。
生成代码
直接运行MyGenerator.java生成代码
注意:每次运行前都要将原来生成的代码删除后在运行生成新的代码,如果不先删除,新生成的代码并不会自动覆盖原来的代码文件而是在原来的代码文件中追加一些不可见的字符导致文件损坏,因此必须先删除在重新生成。
结合当前工程的逆向工程详细代码
黄色部分为重要的修改项:
<?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=“testTables” targetRuntime=“MyBatis3”>
<commentGenerator>
<!– 是否去除自动生成的注释 true:是 : false:否 –>
<property name=“suppressAllComments” value=“true” />
</commentGenerator>
<!–数据库连接的信息:驱动类、连接地址、用户名、密码 –>
<jdbcConnection driverClass=“com.mysql.jdbc.Driver”
connectionURL=“jdbc:mysql://localhost:3306/mybatis” userId=“root”
password=“123”>
</jdbcConnection>
<!– <jdbcConnection driverClass=”oracle.jdbc.OracleDriver”
connectionURL=”jdbc:oracle:thin:@127.0.0.1:1521:yycg”
userId=”yycg”
password=”yycg“>
</jdbcConnection> –>
<!– 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal –>
<javaTypeResolver>
<property name=“forceBigDecimals” value=“false” />
</javaTypeResolver>
<!– targetProject:生成PO类的位置 –>
<javaModelGenerator targetPackage=“cn.itcast.pojo2”
targetProject=“.\src”>
<!– enableSubPackages:是否让schema作为包的后缀 –>
<property name=“enableSubPackages” value=“false” />
<!– 从数据库返回的值被清理前后的空格 –>
<property name=“trimStrings” value=“true” />
</javaModelGenerator>
<!– targetProject:mapper映射文件生成的位置 –>
<sqlMapGenerator targetPackage=“cn.itcast.mapper2”
targetProject=“.\src”>
<!– enableSubPackages:是否让schema作为包的后缀 –>
<property name=“enableSubPackages” value=“false” />
</sqlMapGenerator>
<!– targetPackage:mapper接口生成的位置 –>
<javaClientGenerator type=“XMLMAPPER”
targetPackage=“cn.itcast.mapper2”
targetProject=“.\src”>
<!– enableSubPackages:是否让schema作为包的后缀 –>
<property name=“enableSubPackages” value=“false” />
</javaClientGenerator>
<!– 指定数据库表 –>
<table schema=“” tableName=“user”></table>
<table schema=“” tableName=“order1”></table>
<table schema=“” tableName=“order2”></table>
<!– <table schema=”” tableName=”user”></table> –>
<!– 有些表的字段需要指定java类型
<table schema=”” tableName=”“>
<columnOverride column=”” javaType=”” />
</table> –>
</context>
</generatorConfiguration>
生成的代码:
{width=”1.68503937007874in”
height=”2.751968503937008in”}
把这些代码连同包一起拷贝到sm工程中去测试:
{width=”1.8464566929133859in”
height=”2.4291338582677167in”}
在ApplicationContext.xml的包扫描动态代理配置中追加新的包路径
<bean class=“org.mybatis.spring.mapper.MapperScannerConfigurer”>
<!– 设置扫描的包路径,如果需要扫描多个包,中间用半角逗号隔开 –>
<property name=“basePackage” value=“cn.itcast.mapper,cn.itcast.mapper2” />
</bean>
在【MyTest.java】中添加测试方法
@Test
public void test4() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext(“ApplicationContext.xml”);
// 创建接口的动态代理对象
Order1Mapper order1Mapper = (Order1Mapper)ac.getBean(“order1Mapper”);
// 调用逆向工程生成的接口方法,根据主键查询订单信息
Order1 order1 = order1Mapper.selectByPrimaryKey(“57528381-433e-11e7-ab09-448a5b6dba5c”);
System.out.println(order1.getOrderstatus());
// 调用多条件设置的对象设置条件,然后执行查询
Order1Example example = new Order1Example();
Criteria criteria = example.createCriteria();
List<String> statusList = new ArrayList<String>();
statusList.add(“01”);
statusList.add(“02”);
criteria.andOrderstatusIn(statusList);
criteria.andUseridEqualTo(1001);
List<Order1> orderList = order1Mapper.selectByExample(example);
System.out.println(orderList.size());
}
MyBatis逆向工程的用处
可以快速帮助我们生成每个表对应的pojo,省去了我们手动编写这些没有任何技术含量的pojo的编码工作。
逆向工程还可以帮助我们生成单表的增删改查的操作接口和对应的映射文件,单表的增删改查是与业务无关的,因此逆向工程可以帮助我们生成。我们可以拿过来直接使用。
MyBatis逆向工程注意事项
每次在重新生成前要把原先生成的代码删除,然后在重新生成,不能覆盖。因为覆盖会使覆盖后的文件中生成一些不可见的字符,这些字符你在eclipse中打开是看不到有任何错误的,但一运行就会出错,原因就是这些不可见字符损坏了文件。所以每次生成前要先删除原先生成的所有代码和包目录。
逆向工程只能生成单表的增删改查操作的接口,对于多表关联处理还需要人手工编写。