Mybatis03
一,输入映射和输出映射
输入类型有,简单类型,pojo对象,(参考MyBatis一)
使用POJO包装对象
开发中通过可以使用POJI传递查询条件。查询条件可能是综合的查询条件,不仅包括用户查询条件还包括其他的查询条件。包装对象:Pojo类中的一个属性是另一个的POJO
需求:根据用户名模糊查询用户信息,查询条件放在QueryVo的user属性中。
1.编写QueryVo
1 public class QueryVo { 2 3 // 包含其他的pojo 4 5 private User user; 6 7 public User getUser() { 8 9 return user; 10 11 } 12 13 public void setUser(User user) { 14 15 this.user = user; 16 17 } 18 19 }
2.在UserMapper.xml中配置sql
1 <!-- 使用包装类型查询用户 --> 2 <select id="queryUserByQueryVo" parameterType="QueryVo" resultType="user"> 3 select * from user where username like 4 '%${user.username}%' 5 </select>
3.在UserMapper接口中添加方法:
1 public List<User> queryUserByQueryVo(QueryVo vo);
4.测试
1 @Test 2 public void testQueryUserByQueryVo() { 3 // mybatis和spring整合,整合之后,交给spring管理 4 SqlSession sqlSession = this.sqlSessionFactory.openSession(); 5 // 创建Mapper接口的动态代理对象,整合之后,交给spring管理 6 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 7 // 使用userMapper执行查询,使用包装对象 8 QueryVo queryVo = new QueryVo(); 9 // 设置user条件 10 User user = new User(); 11 user.setUsername("张"); 12 // 设置到包装对象中 13 queryVo.setUser(user); 14 // 执行查询 15 List<User> list = userMapper.queryUserByQueryVo(queryVo); 16 for (User u : list) { 17 System.out.println(u); 18 } 19 // mybatis和spring整合,整合之后,交给spring管理 20 sqlSession.close(); 21 }
效果:
resultMap
resultMap可以指定将查询结果映射为POJO,但需要po'j'o的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询
1.声明POJO对象
1 public class Order { 2 // 订单id 3 private int id; 4 // 用户id 5 private Integer userId; 6 // 订单号 7 private String number; 8 // 订单创建时间 9 private Date createtime; 10 // 备注 11 private String note; 12 get/set。。。 13 }
2.创建orderMapper.xml配置文件
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <!-- 写Sql语句 --> 6 <mapper namespace="com.itheima.mybatis.mapper.OrderMapper"> 7 <!-- 查询所有的订单数据 --> 8 <select id="queryOrderAll" resultType="Order"> 9 select id,user_id,number,createtime, 10 note from orders 11 </select> 12 </mapper>
3.编写Mapper接口
1 public interface OrderMapper { 2 //查询所有订单 3 public List<Order> queryOrderAll(); 4 }
4.编写测试方法
1 public class MybatisOrderTest { 2 private SqlSessionFactory factory; 3 @Before 4 public void init() throws Exception{ 5 InputStream s = Resources.getResourceAsStream("sqlMapConfig.xml"); 6 this.factory = new SqlSessionFactoryBuilder().build(s); 7 } 8 9 @Test 10 public void Test1(){ 11 //获取sqlSession 12 SqlSession session = this.factory.openSession(); 13 //获取orderMapper 14 OrderMapper mapper = session.getMapper(OrderMapper.class); 15 16 //执行查询 17 List<Order> queryOrderAll = mapper.queryOrderAll(); 18 for (Order order : queryOrderAll) { 19 System.out.println(order); 20 } 21 } 22 }
效果:
发现结果是空的,
解决方案1:使用resultMap
解决方案2;造成null原因是Pojo的属性名字,和数据库中的不一致,可以修改成一致的。
使用resultMap
由于上边的mapper.xml中sql查询列(user_id)和Order类属性(userId)不一致,所以查询结果不能映射到pojo中。需要定义resultMap,把orderResultMap将sql查询列(user_id)和Order类属性(userId)对应起来。
改造OrderMapper.xml如下:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 3 <!DOCTYPE mapper 4 5 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 6 7 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 8 9 <!-- 写Sql语句 --> 10 11 <mapper namespace="com.itheima.mybatis.mapper.OrderMapper"> 12 13 <!-- resultMap最后是将结果映射到POJO上,type就是指映射到哪一个pojo 14 15 id:设置ResultMap的id 16 17 定义主键 ,非常重要。如果是多个字段,则定义多个id 18 19 property:主键在pojo中的属性名 20 21 column:主键在数据库中的列名 22 23 --> 24 25 <resultMap type="Order" id="orderResultMap"> 26 27 <id property="id" column="id"/> 28 29 <result property="userId" column="user_id"/> 30 31 <result property="number" column="number"/> 32 33 <result property="createtime" column="createtime"/> 34 35 <result property="note" column="note"/> 36 37 </resultMap> 38 39 <!-- 查询所有的订单数据 --> 40 41 <select id="queryOrderAll" resultType="Order" resultMap="orderResultMap"> 42 43 select id,user_id,number,createtime, 44 45 note from orders 46 47 </select> 48 49 </mapper>
效果:

动态sql
通过mybatis提供的各种标签方法实现动态标签拼接sql
根据性别和名字查询名字
sql:
SELECT id, username, birthday, sex, address FROM `user` WHERE sex = 1 AND username LIKE '%张%'
UserMapper.xml配置sql,如下:
1 <!-- 根据性别和名字查询用户 --> 2 3 <select id="queryUserByWhere" parameterType="User" resultType="User"> 4 5 SELECT id, username, birthday, sex, address FROM user 6 7 WHERE sex = #{sex} AND username LIKE 8 9 '%${username}%' 10 11 </select>
编写Mapper接口:
1 //根据条件查询用户 2 3 public List<User> queryUserByWhere(User u);
测试:
public class MybatisUserTest { private SqlSessionFactory factory; @Before public void init() throws IOException{ InputStream s = Resources.getResourceAsStream("sqlMapConfig.xml"); this.factory = new SqlSessionFactoryBuilder().build(s); } @Test public void TestqueryUserByWhere(){ SqlSession sqlsession = this.factory.openSession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); //执行查询 User u = new User(); u.setUsername("张"); u.setSex("1"); List<User> list = mapper.queryUserByWhere(u); for (User user : list) { System.out.println(user); } } }
效果:

如果注释掉user.setSex("1"),测试结果入下图:

测试结果二很显然不合理。按照之前所学,要解决这个问题,需要编写多个sql,查询条件越多,需要编写的sql就更多了,显然这样是不靠谱的。
解决方法,使用动态sql的if标签
1 <!-- 根据性别和名字查询用户 --> 2 <select id="queryUserByWhere" parameterType="User" resultType="User"> 3 SELECT id, username, birthday, sex, address FROM user 4 WHERE 1=1 5 <if test="sex !=null and sex !=''"> 6 AND sex = #{sex} 7 </if> 8 <if test="username !=null and username !=''"> 9 AND username LIKE '%${username}%' 10 </if> 11 </select>
注意字符串类型的数据需要做不等于空字符校验

上面的sql还有where 1=1 这样的语句,很麻烦。还可以使用where标签来进行改造
<!-- 根据性别和名字查询用户 -->
1 <!-- 根据性别和名字查询用户 --> 2 <select id="queryUserByWhere" parameterType="User" resultType="User"> 3 SELECT id, username, birthday, sex, address FROM user 4 <where> 5 <if test="sex !=null and sex !=''"> 6 AND sex = #{sex} 7 </if> 8 <if test="username !=null and username !=''"> 9 AND username LIKE '%${username}%' 10 </if> 11 </where> 12 </select>
效果:

Sql片段
sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql复用的目的。把上面例子中的id,username,birthday,sex,address提取出来,作为sql片段,如下:
1 <!-- 根据性别和名字查询用户 --> 2 3 <select id="queryUserByWhere" parameterType="User" resultType="User"> 4 5 SELECT <include refid="userFields"></include> FROM user 6 7 <where> 8 9 <if test="sex !=null and sex !=''"> 10 11 AND sex = #{sex} 12 13 </if> 14 15 <if test="username !=null and username !=''"> 16 17 AND username LIKE '%${username}%' 18 19 </if> 20 21 </where> 22 23 </select> 24 25 <sql id="userFields"> 26 27 id,username,birthday,sex,address 28 29 </sql>
如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace
例如:

foreach标签
向sql传递数组或List,mybatis使用foreach解析,如下:根据多个id查询用户信息
查询sql:select * from user where id in(1,10,24)
改造QueryVo
1.在pojo中定义list属性ids 存储多个用户id,并添加get/set

2.在UserMapper.xml中添加:
1 <!-- 查询多个用户 --> 2 3 <select id="queryUserByIds" parameterType="QueryVo" resultType="User"> 4 5 select * from user 6 7 <where> 8 9 <foreach collection="ids" item="id" open="id IN(" close=")" separator=","> 10 11 #{id} 12 13 </foreach> 14 15 </where> 16 17 </select>
3.在UserMapper接口中添加
1 //查询多个用户 2 3 public List<User> queryUserByIds(QueryVo vo); 4 5 4.测试: 6 7 @Test 8 9 public void TestqueryUserByIds(){ 10 11 SqlSession sqlSession = this.factory.openSession(); 12 13 UserMapper mapper = sqlSession.getMapper(UserMapper.class); 14 15 QueryVo vo = new QueryVo(); 16 17 List<Integer> ids = new ArrayList<Integer>(); 18 19 ids.add(1); 20 21 ids.add(10); 22 23 ids.add(24); 24 25 vo.setIds(ids); 26 27 List<User> queryUserByIds = mapper.queryUserByIds(vo); 28 29 for (User user : queryUserByIds) { 30 31 System.out.println(user); 32 33 } 34 35 }
效果:

关联查询
商品订单数据模型

1.一对一查询
需求:查询所有订单信息,关联查询下单用户信息。
注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询,因为一个用户可以下多个订单。
方法一:使用resultType
使用resultType,改造订单POJO类,此pojo类中包括了订单信息和用户信息,这样返回对象的时候,mybatis自动把用户信息也注入进来了。
1.改造pojo类
OrderUser类继承Order类后OrderUser类包括了Order类的所有字段,只需要定义用户的信息字段即可
1 public class OrderUser extends Order{ 2 3 private String username; 4 5 private String address; 6 7 public String getUsername() { 8 9 return username; 10 11 } 12 13 public void setUsername(String username) { 14 15 this.username = username; 16 17 } 18 19 public String getAddress() { 20 21 return address; 22 23 } 24 25 public void setAddress(String address) { 26 27 this.address = address; 28 29 } 30 31 }
2.在UserMapper.xml添加sql,如下
1 <!-- 查询订单,同时包含用户数据 --> 2 <select id="queryOrderUser" resultType="OrderUser"> 3 SELECT 4 o.id, 5 o.user_id userId, 6 o.number, 7 o.createtime, 8 o.note, 9 u.username, 10 u.address 11 FROM 12 orders o 13 LEFT JOIN USER u ON o.user_id = u.id 14 </select>
3.在UserMappring接口中添加对应方法
1 /* 2 * 一对一关联,查询订单同时包含用户信息 3 */ 4 public List<OrderUser> queryOrderUser();
4.测试
1 @Test 2 public void testQueryOrderUser(){ 3 SqlSession sqlsession = this.factory.openSession(); 4 UserMapper mapper = sqlsession.getMapper(UserMapper.class); 5 List<OrderUser> queryOrderUser = mapper.queryOrderUser(); 6 for (OrderUser orderUser : queryOrderUser) { 7 System.out.println(orderUser); 8 } 9 }
5.效果:

方法二:使用resultMap
使用resultMap,定义专门的resultMap用于映射的一对一查询结果
1.改造pojo类
在Order类中加入User属性,user属性中用于存储关联查询的用户信息,因为订单关联查询用户是一对一的关系,所以这里使用单个User对象存储关联查询的用户信息。
1 private User user;
2.在Mapper.xml中添加:
1 <resultMap type="Order" id="orderUserResultMap"> 2 3 <id property="id" column="id"/> 4 5 <result property="userId" column="user_id"/> 6 7 <result property="number" column="number"/> 8 9 <result property="createtime" column="createtime"/> 10 11 <result property="note" column="note"/> 12 13 <!-- association 配置一对一属性 --> 14 15 <!-- property:order里面的user属性名 --> 16 17 <!-- javaType:属性类型 --> 18 19 <association property="user" javaType="User"> 20 21 <!-- id:声明主键,表示user_id是关联查询对象的唯一标识 --> 22 23 <id property="id" column="user_id"/> 24 25 <result property="username" column="username"/> 26 27 <result property="address" column="address"/> 28 29 </association> 30 31 </resultMap> 32 33 <!-- 一对一关联,查询订单,订单内部包含用户属性 --> 34 35 <select id="queryOrderUserResultMap" resultMap="orderUserResultMap"> 36 37 SELECT 38 39 o.id, 40 41 o.user_id, 42 43 o.number, 44 45 o.createtime, 46 47 o.note, 48 49 u.username, 50 51 u.address 52 53 FROM 54 55 orders o 56 57 LEFT JOIN user u ON o.user_id = u.id 58 59 </select>
3.在UserMapper编写接口
1 /* 2 3 * 一对一关联,查询订单同时包含用户信息 4 5 */ 6 7 public List<OrderUser> queryOrderUser();
4.测试
1 @Test 2 3 public void TestqueryOrderUserResultMap(){ 4 5 //获取sqlSession 6 7 SqlSession sqlsession = this.factory.openSession(); 8 9 //获取mapper 10 11 OrderMapper mapper = sqlsession.getMapper(OrderMapper.class); 12 13 14 15 List<Order> list = mapper.queryOrderUserResultMap(); 16 17 for (Order order : list) { 18 19 System.out.println(order); 20 21 } 22 23 }
效果:


浙公网安备 33010602011771号