Mybatis输入输出映射_动态sql_关联关系(一对一、一对多、多对多)
Mybatis输入输出映射_动态sql_关联关系(一对一、一对多、多对多)
输入输出映射
parameterType完成输入映射
parameterType可以传入的参数有,基本数据类型(根据id查询用户的信息)、pojo类型(保存客户信息)、也可以传递pojo包装对象
可以定义pojo包装类型扩展mapper接口输入参数的内容。
需求:
自定义查询条件查询用户信息,需要向statement输入查询条件,查询条件user信息
编写包装数据类型
public class OrderUser extends Order {
// 自定义user的扩展信息
private String username;
private String address;
get/set方法
}
1
2
3
4
5
6
配置mapper.xml
<!-- 根据姓名进行模糊查询通过包装类型 -->
<!--
parameterType:使用别名
resultType:使用别名
-->
<select id="findUserByQureyVo" parameterType="queryVo" resultType="user">
SELECT
`id`,
`username`,
`birthday`,
`sex`,
`address`,
`uuid2`
FROM
USER
WHERE username like '%${user.username}%'
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mapper.java Mapper接口
// 包装类型的测试(模糊查询)
public List<User> findUserByQureyVo(QueryVo vo) throws Exception;
1
2
测试:
private SqlSessionFactory sqlSessionFactory;
// 创建回话工厂
@Before
public void init() throws IOException {
// 1、Mybatis的核心配置文件
String resource = "SqlMapConfig.xml";
// 2、加载Mybatis的配置文件
InputStream is = Resources.getResourceAsStream(resource);
// 3、获取SqlSessionFactory对象,创建会话工厂,加载配置文件到输入 流
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
}
@Test
/**
*
* @Title: testFindUserByQueryVo
* @Description: 模糊插叙用户信息
* @param
* @return void
*/
public void testFindUserByQueryVo() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 根据接口得到实现类的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
QueryVo queryVo = new QueryVo();
User user = new User();
user.setUsername("张");
queryVo.setUser(user);
List<User> list = userMapper.findUserByQureyVo(queryVo);
for (User user2 : list) {
System.out.println(user2);
}
sqlSession.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
resultType输出
返回的是pojo或者List<pojo>返回的类型都是pojo
返回简单数据类型
1、mapper.xml
<!-- 查询总记录数 -->
<select id="findUSerCount" resultType="int">
SELECT COUNT(*) FROM USER
</select>
1
2
3
4
2、配置接口:
// 查询记录总数
public Integer findUSerCount() throws Exception;
1
2
3、测试
public void testFindUserCount() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 根据接口得到实现类的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Integer count = userMapper.findUSerCount();
System.out.println(count);
sqlSession.close();
}
1
2
3
4
5
6
7
8
返回pojo或者List<pojo>
1、mapper.xml
<!-- 模糊查询 -->
<select id="findUserByName" parameterType="String" resultType="user">
SELECT * FROM USER WHERE username like '%${value}%';
</select>
1
2
3
4
2、配置接口:
// 根据id查询用户的信息
public User findUserById(int id) throws Exception;
1
2
3、测试:
// 测试根据Id查询用户信息(得到单个数据)
@Test
public void findUserById() {
// 1、通过sqlSessionFactory创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过sqlSession操作数据库
// 第一个参数:statement的位置,等于namespace+statement的id
// 第二个参数:传入的参数
User user = null;
try {
user = sqlSession.selectOne("user.findUserById", 16);
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
System.out.println(user);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
resultMap输出
resultType(列名和属性名必须一致) :指定输出结果的类型(pojo、简单类型、hashmap…),将sql查询结果映射为java对象 (可以自定义)。
使用resultType注意:sql查询的列名要和resultType指定pojo的属性名相同,指定相同 属性方可映射成功,如果sql查询的列名要和resultType指定pojo的属性名全部不相同,list中无法创建pojo对象的。
resultMap(列名和属性名可以不一致使用映射完成):将sql查询结果映射为java对象。
如果sql查询列名和最终要映射的pojo的属性名不一致,使用resultMap将列名和pojo的属性名做一个对应关系 (列名和属性名映射配置)
需求: 查询出订单的所有信息
问题: Orders的pojo中属性字段和表中的orders的字段有不一致的(user_id和userId)
**分析:**此时我们就不可以简单的说过resultType类型进行返回值的接收,我们可以只用resultMap映射用于接收返回值
1、resultMap配置
<!-- 定义resultMap -->
<resultMap type="order" id="find_order_list">
<!-- 主键 -->
<id property="id" column="id" />
<!--
普通字段用<result>映射
property:pojo中的属性
column:表中对应的字段
-->
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2、使用resultMap
<!--使用resultMap-->
<!--resultMap的值就是定义的resultMap中的id-->
<select id="findOrderListResultMap" resultMap="find_order_list">
SELECT
`id`,
`user_id`,
`number`,
`createtime`,
`note`
FROM
`order`
</select>
1
2
3
4
5
6
7
8
9
10
11
12
3、编写接口:
// 使用resultMap
public List<Order> findOrderListResultMap() throws Exception;
1
2
总结resultType和resultMap
resultType:pojo中的 字段和表中 字段一致的,或者我们可以很方便的自己构建一个pojo类型并解决问题时使用resultType
resultMap: 字段和pojo字段不一致,表结构和关联关系比较复杂的
动态Sql
mybatis重点是对sql的灵活解析和处理。
将自定义查询条件查询用户列表和查询用户列表总记录数改为动态sql
根据传入不同的字段返回结果(名字或者性别查询)传入什么就根据什么进行查询
if和where
<!-- 动态Sql的if和where -->
<select id="findUserByPojo" parameterType="queryVo" resultType="user">
<include refid="user_sql"/>
<!-- <where>自动补上where关键字,同时处理多余and,用了where标签就不能再手动加上where关键字 -->
<where>
<!-- user.username表示从 QueryVo中的user属性取username属性-->
<if test="user.username != null and user.username != '' " >
and username like '%${user.username}%'
</if>
<if test="user.sex != null and user.sex != '' ">
and sex = #{user.sex}
</if>
<!-- 还有别的查询条件 -->
</where>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sql片段
通过sql片段可以将通用的sql语句抽取出来,单独定义,在其它的statement中可以引用sql片段。
通用的sql语句,常用:where条件、查询列
<!--
将用户查询条件定义为sq1片段建议对单表的查询条件单独抽取sq1片段,提高公用性
注意:不要将where标签放在sq1片段
-->
<sql id="user_sql">
SELECT
`id`,
`username`,
`birthday`,
`sex`,
`address`,
`uuid2`
FROM
USER
</sql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sql片段的引用
foreach的使用
在statement通过foreach遍历parameterType中的集合类型。
需求:根据多个用户id查询用户信息。
<!-- 动态Sql的foreach -->
<select id="findUserByIds" parameterType="queryVo" resultType="user">
<include refid="user_sql"/>
<where>
<!-- foreach的使用
id IN(1,22,26,35)
-->
<foreach collection="ids" open="id IN(" item="uid" separator="," close=")" >
#{uid}
</foreach>
</where>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
关联关系
首先创建四张表,字段和关系如下图:
user表:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
orders表:
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
9
10
orderdetail表:
CREATE TABLE `orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orders_id` int(11) NOT NULL COMMENT '订单id',
`items_id` int(11) NOT NULL COMMENT '商品id',
`items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY (`id`),
KEY `FK_orderdetail_1` (`orders_id`),
KEY `FK_orderdetail_2` (`items_id`),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
9
10
11
items表:
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '商品名称',
`price` float(10,1) NOT NULL COMMENT '商品定价',
`detail` text COMMENT '商品描述',
`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
`createtime` datetime NOT NULL COMMENT '生产日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
9
表关系
表关联关系
表分析
用户表user:
记录了购买商品的用户
订单表orders:
记录了用户所创建的订单信息
订单明细表orderdetail:
记录了用户创建订单的详细信息
商品信息表items:
记录了商家提供的商品信息
分析表与表之间的关系:
用户user和订单orders:
user---->orders:一个用户可以创建多个订单 一对多
orders–>user:一个订单只能由一个用户创建 一对一
订单orders和订单明细orderdetail:
orders–>orderdetail:一个订单可以包括多个订单明细 一对多
orderdetail–>orders:一个订单明细只属于一个订单 一对
订单明细orderdetail和商品信息items:
orderdetail–>items:一个订单明细对应一个商品信息 一对一
items–> orderdetail:一个商品对应多个订单明细 一对多
一、查询订单信息关联查询用户信息 一对一 resultType
sql语句的编写
-- 首先确定主表:user
-- 找到关联的从表:orders
-- 找出两者之间的关系 orders.`user_id`= user.`id`
SELECT
o.* ,
u.`username`,
u.`address`
FROM
orders o,
USER u
WHERE
o.`user_id`= u.`id`
1
2
3
4
5
6
7
8
9
10
11
12
使用resultType实现
首先实现基础的pojo
一对一查询映射的pojo:
创建pojo包括 订单信息和用户信息,resultType才可以完成映射。
创建OrderCustom作为自定义pojo,继承sql查询列多的po类。
public class OrderCustomer extends Orders {
//补充用户信息
private String username;
private String address;
}
1
2
3
4
5
6
定义mapper.xml文件
<!-- 一、查询订单信息关联查询用户信息 一对一 resultType -->
<select id="findOrderMapperCustomer" resultType="orderCustomer" >
SELECT
o.* ,
u.`username`,
u.`address`
FROM
orders o,
USER u
WHERE
o.`user_id`= u.`id`
</select>
1
2
3
4
5
6
7
8
9
10
11
12
mapper.java
// 一、查询订单信息关联查询用户信息 一对一 使用resultType
public List<OrderCustomer> findOrderMapperCustomer() throws Exception;
1
2
二、查询订单信息关联查询用户信息 一对一 使用resultMap
resultMap映射思路
resultMap提供一对一关联查询的映射和一对多关联查询映射,一对一映射思路:将关联查询的信息映射到pojo中,如下:
在Orders类中创建一个User属性,将关联查询的信息映射到User属性中。
sql语句的编写
SELECT
o.* ,
u.`username`,
u.`address`
FROM
orders o,
USER u
WHERE
o.`user_id`= u.`id`
1
2
3
4
5
6
7
8
9
定义resultMap
<!-- 二、查询订单信息关联查询用户信息 一对一 resultMap -->
<resultMap type="orders" id="order_mapper_customer">
<!-- 完成订单信息的映射配置 -->
<!-- id订单关联用户查询的唯一标识 -->
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
<!-- 关联关系的信息映射
association:用于对关联信息映射到单个pojo
property:要将关联信息映射到orders的那个属性
javaType:关联信息映射到orders的属性的类型,是user类型
-->
<association property="user" javaType="com.syj.mybatis.pojo.User" >
<!-- id:关联信息的唯一标识 -->
<!-- property:要映射到user的那个属性中 -->
<id property="id" column="user_id" />
<!-- result:就是普通属性的列 -->
<result property="username" column="username" />
<result property="address" column="address" />
</association>
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
在mapper.xml使用定义的resultMap
<!-- 一对一查询使用resultMap完成订单关联查询用户的信息 -->
<select id="findOrderMapperCustomerResultMap" resultMap="order_mapper_customer">
SELECT
o.* ,
u.`username`,
u.`address`
FROM
orders o,
USER u
WHERE
o.`user_id`= u.`id`
</select>
1
2
3
4
5
6
7
8
9
10
11
12
编写mapper接口
// 二、查询订单信息关联查询用户信息 一对一 使用resultMap
public List<Orders> findOrderMapperCustomerResultMap() throws Exception;
1
2
小结
resultType:要自定义pojo 保证sql查询列和pojo的属性对应,这种方法相对较简单,所以应用广泛。
resultMap:使用association完成一对一映射需要配置一个resultMap,过程有点复杂,如果要实现延迟加载就只能用resultMap实现 ,如果为了方便对关联信息进行解析,也可以用association将关联信息映射到pojo中方便解析。
三、查询订单信息关联用户信息的订单详情 一对多 使用resultMap
sql语句的编写
SELECT
o.* ,
u.`username`,
u.`address`,
od.`orders_id` ordersid,
od.`items_id` itemsid,
od.`items_num` itemsnum
FROM
orders o,
USER u,
orderdetail od
WHERE
o.`user_id`= u.`id` AND od.`orders_id`= o.`id`
1
2
3
4
5
6
7
8
9
10
11
12
13
定义resultMap
<!--三、查询订单信息关联查询用户信息 一对多 resultMap -->
<resultMap type="orders" id="order_mapper_orderDetail" extends="order_mapper_customer">
<!-- 映射订单信息和用户信息,这里使用继承 order_mapper_customer -->
<!-- 映射订单明细
property :将要关联的信息映射到orders的那个属性
ofType :集合中Pojo的类型
-->
<collection property="orderdetails" ofType="Orderdetail">
<!-- 关联订单明细的唯一标识
property:Orderdetail的属性名
-->
<id property="id" column="ordersid" />
<result property="itemsId" column="itemsid" />
<result property="itemsNum" column="itemsnum" />
</collection>
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在mapper.xml使用定义的resultMap
<select id="findOrderMapperOrderDetailResultMap" resultMap="order_mapper_orderDetail">
SELECT
o.* ,
u.`username`,
u.`address`,
od.`orders_id` ordersid,
od.`items_id` itemsid,
od.`items_num` itemsnum
FROM
orders o,
USER u,
orderdetail od
WHERE
o.`user_id`= u.`id` AND od.`orders_id`= o.`id`
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
编写mapper接口
// 三、查询订单信息关联用户信息的订单详情 一对多 使用resultMap
public List<Orders> findOrderMapperOrderDetailResultMap() throws Exception;
1
2
四、查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息
用户中包含订单,一个用户对应多个订单
订单中包含订单详情,一个订单详情对应多个订单详情
订单详情中包含商品,一个订单详情中包含一个商品
sql语句的编写
SELECT
u.*,
o.`id` order_id,
o.`number`,
o.`createtime`,
od.`id` orderdetail_id,
od.`items_id`,
od.`items_num`,
i.`name` ,
i.`detail`
FROM
`user` u,
orders o,
orderdetail od,
items i
WHERE u.`id` = o.`user_id` AND o.`id` = od.`orders_id` AND od.`items_id` = i.`id`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
定义resultMap
<!-- 四、一对多的复杂查询
查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息
-->
<resultMap type="user" id="user_orders_ordersdetail_item">
<!-- 用户信息映射 -->
<!-- -->
<id property="id" column="id" />
<result property="username" column="username" />
<result property="sex" column="sex" />
<result property="birthday" column="birthday" />
<result property="address" column="address" />
<!-- 订单信息 -->
<collection property="orders" ofType="Orders" >
<id property="id" column="order_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<!-- 订单明细 -->
<collection property="orderdetails" ofType="Orderdetail" >
<id property="id" column="orderdetail_id" />
<result property="itemsId" column="items_id" />
<result property="itemsNum" column="items_num" />
<!-- 商品信息 -->
<association property="items" javaType="Items" >
<id property="id" column="items_id" />
<result property="name" column="name" />
<result property="detail" column="detail" />
</association>
</collection>
</collection>
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
在mapper.xml使用定义的resultMap
<select id="findUserOrdersOrderDetailItem" resultMap="user_orders_ordersdetail_item">
SELECT
u.*,
o.`id` order_id,
o.`number`,
o.`createtime`,
od.`id` orderdetail_id,
od.`items_id`,
od.`items_num`,
i.`name` ,
i.`detail`
FROM
`user` u,
orders o,
orderdetail od,
items i
WHERE u.`id` = o.`user_id` AND o.`id` = od.`orders_id` AND od.`items_id` = i.`id`
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
编写mapper接口
// 四、查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息
public List<User> findUserOrdersOrderDetailItem() throws Exception;
1
2
练习一:用户账号、用户名称、用户性别、商品名称、商品价格(最常见)resultType类型
sql语句的编写
SELECT
u.`id`,
u.`username`,
u.`sex`,
i.`name`,
i.`price`
FROM
USER u,
orders o,
orderdetail od,
items i
WHERE u.`id` = o.`user_id` AND o.`id` = od.`orders_id` AND od.`items_id` = i.`id`
1
2
3
4
5
6
7
8
9
10
11
12
13
在mapper.xml使用
<!-- 练习一:用户账号、用户名称、用户性别、商品名称、商品价格(最常见)resultType类型 -->
<select id="findUserItem" resultType="UserItem">
SELECT
u.`id`,
u.`username`,
u.`sex`,
i.`name`,
i.`price`
FROM
USER u,
orders o,
orderdetail od,
items i
WHERE u.`id` = o.`user_id` AND o.`id` = od.`orders_id` AND od.`items_id` = i.`id`
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
编写mapper接口
// 练习一:用户账号、用户名称、用户性别、商品名称、商品价格(最常见)
public List<UserItem> findUserItem() throws Exception;
1
2
练习二:用户账号、用户名称、购买商品数量、商品明细
sql语句的编写
SELECT
u.`id`,
u.`username`,
od.`items_num` num,
i.`name`,
i.`price`,
i.`detail`,
i.`createtime`
FROM
USER u,
orders o,
orderdetail od,
items i
WHERE
u.`id` = o.`user_id` AND o.`id` = od.`orders_id` AND od.`items_id` = i.`id`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
定义resultMap
<!-- 练习二:用户账号、用户名称、购买商品数量、商品明细 -->
<resultMap type="user" id="user_items">
<!-- 用户的映射配置 -->
<id property="id" column="id" />
<result property="username" column="username" />
<!-- 订单的配置 -->
<collection property="orders" ofType="Orders" >
<!-- 订单详情的映射 -->
<collection property="orderdetails" ofType="Orderdetail">
<result property="itemsNum" column="num" />
<!-- 商品的映射 -->
<association property="items" javaType="Items">
<result property="name" column="name" />
<result property="price" column="price" />
<result property="detail" column="detail" />
<result property="createtime" column="createtime" />
</association>
</collection>
</collection>
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在mapper.xml使用定义的resultMap
<select id="findUserItems" resultMap="user_items" >
SELECT
u.`id`,
u.`username`,
od.`items_num` num,
i.`name`,
i.`price`,
i.`detail`,
i.`createtime`
FROM
USER u,
orders o,
orderdetail od,
items i
WHERE
u.`id` = o.`user_id` AND o.`id` = od.`orders_id` AND od.`items_id` = i.`id`
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
编写mapper接口
// 练习二:用户账号、用户名称、购买商品数量、商品明细(
public List<User> findUserItems() throws Exception;
1
2
resultMap:也是对查询结果集进行输出映射,根据自己需求可以通过resultMap将查询结果集映射到pojo中pojo属性中,还可以将多条记录结果集映射到pojo中List集合属性中。一对多、多对多、一对多这是针对业务来说的,可以写成符合一对一、一对多、多对多业务的sql语句,sql语句的结果集的映射由mybatis完成。写成一个复杂的多对多的sql语句,使用resultMap或resultType完成结果集映射。
---------------------