mybatis和逆向工程

Mybatis第二天

框架课程

  1. 课程计划
    1、输入映射和输出映射
    a) 输入参数映射
    b) 返回值映射
    2、动态sql
    a) If标签
    b) Where标签
    c) Sql片段
    d) Foreach标签
    3、关联查询
    a) 一对一关联
    b) 一对多关联
    4、Mybatis整合spring
    a) 如何整合spring
    b) 使用原始的方式开发dao
    c) 使用Mapper接口动态代理
    5、Mybatis逆向工程
  2. 输入映射和输出映射
    Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
    2.1. 环境准备
    创建Maven工程,并加入以下依赖:


    mysql
    mysql-connector-java
    5.1.46


    org.mybatis
    mybatis
    3.2.7


    org.slf4j
    slf4j-log4j12
    1.7.25


    junit
    junit
    4.12

复制前一天课程的配置文件到新工程
SqlMapConfig.xml
log4j.properties
UserMapper.xml

复制前一天的代码到新工程
User
UserMapper
UserMapperTest

测试可以正常使用

2.2. parameterType(输入类型)
2.2.1. 传递简单类型
参考第一天内容。
使用#{}占位符,或者${}进行sql拼接。

2.2.2. 传递pojo对象
参考第一天的内容。
Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。

2.2.3. 传递pojo包装对象
开发中通过可以使用pojo传递查询条件。
查询条件可能是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如查询用户信息的时候,将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
包装对象:Pojo类中的一个属性是另外一个pojo。

需求:根据用户名模糊查询用户信息,查询条件放到QueryVo的user属性中。

2.2.3.1. 编写QueryVo
public class QueryVo {
// 包含其他的pojo
private User user;

public User getUser() {
	return user;
}
public void setUser(User user) {
	this.user = user;
}

}

2.2.3.2. Sql语句
SELECT * FROM user WHERE username LIKE ‘%张%’
2.2.3.3. Mapper.xml文件
在UserMapper.xml中配置sql,如下图。
在这里插入图片描述
2.2.3.4. Mapper接口
在UserMapper接口中添加方法,如下图:
在这里插入图片描述
2.2.3.5. 测试方法
在UserMapperTest增加测试方法,如下:
@Test
public void testQueryUserByQueryVo() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 使用userMapper执行查询,使用包装对象
QueryVo queryVo = new QueryVo();
// 设置user条件
User user = new User();
user.setUsername("张");
// 设置到包装对象中
queryVo.setUser(user);

// 执行查询
List<User> list = userMapper.queryUserByQueryVo(queryVo);
for (User u : list) {
	System.out.println(u);
}

// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();

}

2.2.3.6. 效果
测试结果如下图:
在这里插入图片描述

2.3. resultType(输出类型)
2.3.1. 输出简单类型
需求:查询用户表数据条数

sql:SELECT count(*) FROM user

2.3.1.1. Mapper.xml文件
在UserMapper.xml中配置sql,如下图:

在这里插入图片描述
2.3.1.2. Mapper接口
在UserMapper添加方法,如下图:

在这里插入图片描述
2.3.1.3. 测试方法
在UserMapeprTest增加测试方法,如下:
@Test
public void testQueryUserCount() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 使用userMapper执行查询用户数据条数
int count = userMapper.queryUserCount();
System.out.println(count);

// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();

}

2.3.1.4. 效果
测试结果如下图:
在这里插入图片描述
注意:输出简单类型必须查询出来的结果集只有一条记录,最终将第一个字段的值转换为输出类型。

2.3.2. 输出pojo对象
参考第一天内容
2.3.3. 输出pojo列表
参考第一天内容。
2.4. resultMap
resultType可以指定将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。

需求:查询订单表order的所有数据
sql:SELECT id, user_id, number, createtime, note FROM order
2.4.1. 声明pojo对象
数据库表如下图:
在这里插入图片描述

Order对象:
public class Order {
// 订单id
private int id;
// 用户id
private Integer userId;
// 订单号
private String number;
// 订单创建时间
private Date createtime;
// 备注
private String note;
get/set。。。
toString();
}
2.4.2. Mapper.xml文件
创建OrderMapper.xml配置文件,如下:

<?xml version="1.0" encoding="UTF-8" ?> SELECT id, user_id, number, createtime, note FROM `order`

2.4.3. Mapper接口
编写接口如下:
public interface OrderMapper {
/**
* 查询所有订单
*
* @return
*/
List queryOrderAll();
}

2.4.4. 测试方法
编写测试方法OrderMapperTest如下:
public class OrderMapperTest {
private SqlSessionFactory sqlSessionFactory;

@Before
public void init() throws Exception {
	InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
	this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}

@Test
public void testQueryAll() {
	// 获取sqlSession
	SqlSession sqlSession = this.sqlSessionFactory.openSession();
	// 获取OrderMapper
	OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);

	// 执行查询
	List<Order> list = orderMapper.queryOrderAll();
	for (Order order : list) {
		System.out.println(order);
	}
}

}

2.4.5. 效果
测试效果如下图:
在这里插入图片描述
发现userId为null
解决方案:使用resultMap

2.4.6. 使用resultMap
由于上边的mapper.xml中sql查询列(user_id)和Order类属性(userId)不一致,所以查询结果不能映射到pojo中。
需要定义resultMap,把orderResultMap将sql查询列(user_id)和Order类属性(userId)对应起来

改造OrderMapper.xml,如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
<!-- id:设置ResultMap的id -->
<resultMap type="order" id="orderResultMap">
	<!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
	<!-- property:主键在pojo中的属性名 -->
	<!-- column:主键在数据库中的列名 -->
	<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" />
</resultMap>

<!-- 查询所有的订单数据 -->
<select id="queryOrderAll" resultMap="orderResultMap">
	SELECT id, user_id,
	number,
	createtime, note FROM `order`
</select>

2.4.7. 效果
只需要修改Mapper.xml就可以了,再次测试结果如下:

在这里插入图片描述
3. 动态sql
通过mybatis提供的各种标签方法实现动态拼接sql。

需求:根据性别和名字查询用户
查询sql:
SELECT id, username, birthday, sex, address FROM user WHERE sex = 1 AND username LIKE ‘%张%’
3.1. If标签
3.1.1. Mapper.xml文件
UserMapper.xml配置sql,如下:

SELECT id, username, birthday, sex, address FROM `user` WHERE sex = #{sex} AND username LIKE '%${username}%'

3.1.2. Mapper接口
编写Mapper接口,如下图:

在这里插入图片描述
3.1.3. 测试方法
在UserMapperTest添加测试方法,如下:
@Test
public void testQueryUserByWhere() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 使用userMapper执行根据条件查询用户
User user = new User();
user.setSex("1");
user.setUsername("张");

List<User> list = userMapper.queryUserByWhere(user);

for (User u : list) {
	System.out.println(u);
}

// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();

}

3.1.4. 效果
测试效果如下图:
在这里插入图片描述

如果注释掉 user.setSex(“1”),测试结果如下图:
在这里插入图片描述

测试结果二很显然不合理。
按照之前所学的,要解决这个问题,需要编写多个sql,查询条件越多,需要编写的sql就更多了,显然这样是不靠谱的。

解决方案,使用动态sql的if标签

3.1.5. 使用if标签
改造UserMapper.xml,如下:

SELECT id, username, birthday, sex, address FROM `user` WHERE 1=1 AND sex = #{sex} AND username LIKE '%${username}%'

注意字符串类型的数据需要要做不等于空字符串校验。
3.1.6. 效果
在这里插入图片描述
如上图所示,测试OK

3.2. Where标签
上面的sql还有where 1=1 这样的语句,很麻烦
可以使用where标签进行改造

改造UserMapper.xml,如下

SELECT id, username, birthday, sex, address FROM `user` AND sex = #{sex} AND username LIKE '%${username}%'

3.2.1. 效果
测试效果如下图:
在这里插入图片描述

3.3. Sql片段
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。

把上面例子中的id, username, birthday, sex, address提取出来,作为sql片段,如下:

SELECT FROM `user` AND sex = #{sex} AND username LIKE '%${username}%' id, username, birthday, sex, address

如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace
例如下图
在这里插入图片描述
3.4. foreach标签
向sql传递数组或List,mybatis使用foreach解析,如下:

根据多个id查询用户信息
查询sql:
SELECT * FROM user WHERE id IN (1,10,24)

3.4.1. 改造QueryVo
如下图在pojo中定义list属性ids存储多个用户id,并添加getter/setter方法
在这里插入图片描述

3.4.2. Mapper.xml文件
UserMapper.xml添加sql,如下:

SELECT * FROM `user` #{item}

测试方法如下图:
@Test
public void testQueryUserByIds() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 使用userMapper执行根据条件查询用户
QueryVo queryVo = new QueryVo();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(10);
ids.add(24);
queryVo.setIds(ids);

List<User> list = userMapper.queryUserByIds(queryVo);

for (User u : list) {
	System.out.println(u);
}

// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();

}

3.4.3. 效果
测试效果如下图:
在这里插入图片描述

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

4.2. 一对一查询
需求:查询所有订单信息,关联查询下单用户信息。

注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询,因为一个用户可以下多个订单。

sql语句:
SELECT
o.id,
o.user_id userId,
o.number,
o.createtime,
o.note,
u.username,
u.address
FROM
order o
LEFT JOIN user u ON o.user_id = u.id

4.2.1. 方法一:使用resultType
使用resultType,改造订单pojo类,此pojo类中包括了订单信息和用户信息
这样返回对象的时候,mybatis自动把用户信息也注入进来了
4.2.1.1. 创建pojo类
OrderUser类继承Order类后OrderUser类包括了Order类的所有字段,只需要定义用户的信息字段即可,如下图:
在这里插入图片描述
4.2.1.2. Mapper.xml
在UserMapper.xml添加sql,如下

SELECT o.id, o.user_id userId, o.number, o.createtime, o.note, u.username, u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id

4.2.1.3. Mapper接口
在UserMapper接口添加方法,如下图:
在这里插入图片描述
4.2.1.4. 测试方法:
在UserMapperTest添加测试方法,如下:
@Test
public void testQueryOrderUser() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 使用userMapper执行根据条件查询用户
List<OrderUser> list = userMapper.queryOrderUser();

for (OrderUser ou : list) {
	System.out.println(ou);
}

// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();

}

4.2.1.5. 效果
测试结果如下图:
在这里插入图片描述
4.2.1.6. 小结
定义专门的pojo类作为输出类型,其中定义了sql查询结果集所有的字段。此方法较为简单,企业中使用普遍。

4.2.2. 方法二:使用resultMap
使用resultMap,定义专门的resultMap用于映射一对一查询结果。

4.2.2.1. 改造pojo类
在Order类中加入User属性,user属性中用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个User对象存储关联查询的用户信息。
改造Order如下图:
在这里插入图片描述

4.2.2.2. Mapper.xml
这里resultMap指定orderUserResultMap,如下:





<!-- association :配置一对一属性 -->
<!-- property:order里面的User属性名 -->
<!-- javaType:属性类型 -->
<association property="user" javaType="user">
	<!-- id:声明主键,表示user_id是关联查询对象的唯一标识-->
	<id property="id" column="user_id" />
	<result property="username" column="username" />
	<result property="address" column="address" />
</association>
SELECT o.id, o.user_id, o.number, o.createtime, o.note, u.username, u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id

4.2.2.3. Mapper接口
编写UserMapper如下图:
在这里插入图片描述

4.2.2.4. 测试方法
在UserMapperTest增加测试方法,如下:
@Test
public void testQueryOrderUserResultMap() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 使用userMapper执行根据条件查询用户
List<Order> list = userMapper.queryOrderUserResultMap();

for (Order o : list) {
	System.out.println(o);
}

// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();

}
4.2.2.5. 效果
测试效果如下图:
在这里插入图片描述

4.3. 一对多查询
案例:查询所有用户信息及用户关联的订单信息。
用户信息和订单信息为一对多关系。

sql语句:
SELECT
u.id,
u.username,
u.birthday,
u.sex,
u.address,
o.id oid,
o.number,
o.createtime,
o.note
FROM
user u
LEFT JOIN order o ON u.id = o.user_id

4.3.1. 修改pojo类
在User类中加入List orders属性,如下图:
在这里插入图片描述

4.3.2. Mapper.xml
在UserMapper.xml添加sql,如下:





<!-- 配置一对多的关系 -->
<collection property="orders" javaType="list" ofType="order">
	<!-- 配置主键,是关联Order的唯一标识 -->
	<id property="id" column="oid" />
	<result property="number" column="number" />
	<result property="createtime" column="createtime" />
	<result property="note" column="note" />
</collection>
SELECT u.id, u.username, u.birthday, u.sex, u.address, o.id oid, o.number, o.createtime, o.note FROM `user` u LEFT JOIN `order` o ON u.id = o.user_id

4.3.3. Mapper接口
编写UserMapper接口,如下图:
在这里插入图片描述

4.3.4. 测试方法
在UserMapperTest增加测试方法,如下
@Test
public void testQueryUserOrder() {
// mybatis和spring整合,整合之后,交给spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 创建Mapper接口的动态代理对象,整合之后,交给spring管理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 使用userMapper执行根据条件查询用户
List<User> list = userMapper.queryUserOrder();

for (User u : list) {
	System.out.println(u);
}

// mybatis和spring整合,整合之后,交给spring管理
sqlSession.close();

}

4.3.5. 效果
测试效果如下图:

在这里插入图片描述

  1. Mybatis逆向工程
    使用官方网站的Mapper自动生成工具mybatis-generator-core-1.3.2来生成po类和Mapper映射文件
    5.1. 导入逆向工程
    使用课前资料已有逆向工程,如下图:
    在这里插入图片描述

5.1.1. 复制逆向工程到工作空间中
复制的效果如下图:
在这里插入图片描述

5.1.2. 导入逆向工程到eclipse中
如下图方式进行导入:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5.2. 修改配置文件
在generatorConfig.xml中配置Mapper生成的详细信息,如下图:
在这里插入图片描述
注意修改以下几点:

  1. 修改要生成的数据库表
  2. pojo文件所在包路径
  3. Mapper所在的包路径

配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
	<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 
		和 NUMERIC 类型解析为java.math.BigDecimal -->
	<javaTypeResolver>
		<property name="forceBigDecimals" value="false" />
	</javaTypeResolver>

	<!-- targetProject:生成PO类的位置 -->
	<javaModelGenerator targetPackage="cn.itcast.ssm.po"
		targetProject=".\src">
		<!-- enableSubPackages:是否让schema作为包的后缀 -->
		<property name="enableSubPackages" value="false" />
		<!-- 从数据库返回的值被清理前后的空格 -->
		<property name="trimStrings" value="true" />
	</javaModelGenerator>
	<!-- targetProject:mapper映射文件生成的位置 -->
	<sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
		targetProject=".\src">
		<!-- enableSubPackages:是否让schema作为包的后缀 -->
		<property name="enableSubPackages" value="false" />
	</sqlMapGenerator>
	<!-- targetPackage:mapper接口生成的位置 -->
	<javaClientGenerator type="XMLMAPPER"
		targetPackage="cn.itcast.ssm.mapper" targetProject=".\src">
		<!-- enableSubPackages:是否让schema作为包的后缀 -->
		<property name="enableSubPackages" value="false" />
	</javaClientGenerator>
	<!-- 指定数据库表 -->
	<table schema="" tableName="user"></table>
	<table schema="" tableName="order"></table>
</context>
5.3. 生成逆向工程代码 找到下图所示的java文件,执行工程main主函数, ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190213215557701.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190213215607335.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDY1NDM3NQ==,size_16,color_FFFFFF,t_70)

刷新工程,发现代码生成,如下图:
在这里插入图片描述
5.4. 测试逆向工程代码

  1. 复制生成的代码到mybatis-spring工程,如下图
    在这里插入图片描述

  2. 修改spring配置文件
    在applicationContext.xml修改

  1. 编写测试方法:
    public class UserMapperTest {
    private ApplicationContext context;

    @Before
    public void setUp() throws Exception {
    this.context = new ClassPathXmlApplicationContext(“classpath:applicationContext.xml”);
    }

    @Test
    public void testInsert() {
    // 获取Mapper
    UserMapper userMapper = this.context.getBean(UserMapper.class);

     User user = new User();
     user.setUsername("曹操");
     user.setSex("1");
     user.setBirthday(new Date());
     user.setAddress("三国");
    
     userMapper.insert(user);
    

    }

    @Test
    public void testSelectByExample() {
    // 获取Mapper
    UserMapper userMapper = this.context.getBean(UserMapper.class);

     // 创建User对象扩展类,用户设置查询条件
     UserExample example = new UserExample();
     example.createCriteria().andUsernameLike("%张%");
    
     // 查询数据
     List<User> list = userMapper.selectByExample(example);
    
     System.out.println(list.size());
    

    }

    @Test
    public void testSelectByPrimaryKey() {
    // 获取Mapper
    UserMapper userMapper = this.context.getBean(UserMapper.class);

     User user = userMapper.selectByPrimaryKey(1);
     System.out.println(user);
    

    }
    }

注意:

  1. 逆向工程生成的代码只能做单表操作
  2. 不能在生成的代码上进行扩展,因为如果数据库变更,需要重新使用逆向工程生成代码,原来编写的代码就被覆盖了。
  3. 一张表会生成4个文件

猜你喜欢

转载自blog.csdn.net/weixin_44654375/article/details/87211121