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 >
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 >
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 >
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" />
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2、使用resultMap
<!--使用resultMap-->
<!--resultMap的值就是定义的resultMap中的id-->
<select >
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 >
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 >
#{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 >
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" />
</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 >
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" />
</collection>
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在mapper.xml使用定义的resultMap
<select >
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" />
</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 >
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 >
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" />
</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 >
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完成结果集映射。
---------------------