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 }

效果:

 

 

posted @ 2018-11-02 10:34  武小白  阅读(126)  评论(0)    收藏  举报