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方法 }
-
配置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>
-
mapper.java Mapper接口
// 包装类型的测试(模糊查询) public List<User> findUserByQureyVo(QueryVo vo) throws Exception;
-
测试:
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(); }
-
resultType输出
-
返回的是pojo或者List<pojo>返回的类型都是pojo
-
返回简单数据类型
1、mapper.xml
<!-- 查询总记录数 --> <select id="findUSerCount" resultType="int"> SELECT COUNT(*) FROM USER </select>
2、配置接口:
// 查询记录总数 public Integer findUSerCount() throws Exception;
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(); }
-
返回pojo或者List<pojo>
1、mapper.xml
<!-- 模糊查询 --> <select id="findUserByName" parameterType="String" resultType="user"> SELECT * FROM USER WHERE username like '%${value}%'; </select>
2、配置接口:
// 根据id查询用户的信息 public User findUserById(int id) throws Exception;
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); }
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>
2、使用resultMap
<!--使用resultMap--> <!--resultMap的值就是定义的resultMap中的id--> <select id="findOrderListResultMap" resultMap="find_order_list"> SELECT `id`, `user_id`, `number`, `createtime`, `note` FROM `order` </select>
3、编写接口:
// 使用resultMap public List<Order> findOrderListResultMap() throws Exception;
-
总结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>
- 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>
-
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>
关联关系
-
首先创建四张表,字段和关系如下图:
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;
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;
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;
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;
-
表关系
-
表关联关系
-
表分析
用户表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`
-
使用resultType实现
首先实现基础的pojo
-
一对一查询映射的pojo:
创建pojo包括 订单信息和用户信息,resultType才可以完成映射。
创建OrderCustom作为自定义pojo,继承sql查询列多的po类。
public class OrderCustomer extends Orders { //补充用户信息 private String username; private String address; }
-
定义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>
-
mapper.java
// 一、查询订单信息关联查询用户信息 一对一 使用resultType public List<OrderCustomer> findOrderMapperCustomer() throws Exception;
二、查询订单信息关联查询用户信息 一对一 使用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`
-
定义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>
-
在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>
-
编写mapper接口
// 二、查询订单信息关联查询用户信息 一对一 使用resultMap public List<Orders> findOrderMapperCustomerResultMap() throws Exception;
-
小结
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`
-
定义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>
-
在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>
-
编写mapper接口
// 三、查询订单信息关联用户信息的订单详情 一对多 使用resultMap public List<Orders> findOrderMapperOrderDetailResultMap() throws Exception;
四、查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息
-
用户中包含订单,一个用户对应多个订单
-
订单中包含订单详情,一个订单详情对应多个订单详情
-
订单详情中包含商品,一个订单详情中包含一个商品
-
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`
-
定义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>
-
在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>
-
编写mapper接口
// 四、查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息 public List<User> findUserOrdersOrderDetailItem() throws Exception;
练习一:用户账号、用户名称、用户性别、商品名称、商品价格(最常见)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`
-
在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>
-
编写mapper接口
// 练习一:用户账号、用户名称、用户性别、商品名称、商品价格(最常见) public List<UserItem> findUserItem() throws Exception;
练习二:用户账号、用户名称、购买商品数量、商品明细
-
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`
-
定义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>
-
在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>
-
编写mapper接口
// 练习二:用户账号、用户名称、购买商品数量、商品明细( public List<User> findUserItems() throws Exception;
-
resultMap:也是对查询结果集进行输出映射,根据自己需求可以通过resultMap将查询结果集映射到pojo中pojo属性中,还可以将多条记录结果集映射到pojo中List集合属性中。一对多、多对多、一对多这是针对业务来说的,可以写成符合一对一、一对多、多对多业务的sql语句,sql语句的结果集的映射由mybatis完成。写成一个复杂的多对多的sql语句,使用resultMap或resultType完成结果集映射。