mybatis在项目中的使用

mybatis在项目中的使用

一、mybatis开发dao层

使用MyBatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper动态代理开发方法。

1.1 SqlSession的使用范围

  • SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
  • SqlSession通过SqlSessionFactory创建。
  • SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

1.1.1 SqlSessionFactoryBuilder

    SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

1.1.2 SqlSessionFactory

    SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。

1.1.3 SqlSession

    SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。
    每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
       打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:

SqlSession session = sqlSessionFactory.openSession();
try {
	 // do work
} finally {
	session.close();
}

1.2 原始Dao开发方式

    原始Dao开发方法需要程序员编写Dao接口和Dao实现类

1.2.1 编写映射文件

采用mybatis的基础入门里面的映射文件mybatis的基础入门

1.2.2 Dao接口

public interface UserDao {
	//根据id查询用户
	User queryUserById(int id);
	//根据用户名模糊查询用户
	List<User> queryUserByUsername(String username);
	//保存用户
	void saveUser(User user);
}

1.2.3 Dao的实现类

public class UserDaoImpl implements UserDao {
	private SqlSessionFactory sqlSessionFactory;
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
		super();
		this.sqlSessionFactory = sqlSessionFactory;
	}
	@Override
	public User queryUserById(int id) {
		// 创建SqlSession
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 执行查询逻辑
		User user = sqlSession.selectOne("queryUserById", id);
		// 释放资源
		sqlSession.close();

		return user;
	}
	@Override
	public List<User> queryUserByUsername(String username) {
		// 创建SqlSession
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 执行查询逻辑
		List<User> list = sqlSession.selectList("queryUserByUsername", username);
		// 释放资源
		sqlSession.close();
		return list;
	}
	@Override
	public void saveUser(User user) {
		// 创建SqlSession
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 执行保存逻辑
		sqlSession.insert("saveUser", user);
		// 提交事务
		sqlSession.commit();
		// 释放资源
		sqlSession.close();
	}
}

1.2.4 Dao测试

创建一个JUnit的测试类,对UserDao进行测试,测试代码如下:

public class UserDaoTest {
	private SqlSessionFactory sqlSessionFactory;
	@Before
	public void init() throws Exception {
		// 创建SqlSessionFactoryBuilder
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		// 加载SqlMapConfig.xml配置文件
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
		// 创建SqlsessionFactory
		this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
	}
	@Test
	public void testQueryUserById() {
		// 创建DAO
		UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
		// 执行查询
		User user = userDao.queryUserById(1);
		System.out.println(user);
	}
	@Test
	public void testQueryUserByUsername() {
		// 创建DAO
		UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
		// 执行查询
		List<User> list = userDao.queryUserByUsername("张");
		for (User user : list) {
			System.out.println(user);
		}
	}
	@Test
	public void testSaveUser() {
		// 创建DAO
		UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
		// 创建保存对象
		User user = new User();
		user.setUsername("刘备");
		user.setBirthday(new Date());
		user.setSex("1");
		user.setAddress("蜀国");
		// 执行保存
		userDao.saveUser(user);
		System.out.println(user);
	}
}

1.2.5 问题

原始Dao开发中存在以下问题:
    Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
    调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护

1.3 Mapper动态代理方式(重点)

1.3.1 开发规范

    Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
    Mapper接口开发需要遵循以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

1.3.2 Mapper.xml(映射文件)

定义mapper映射文件UserMapper.xml,将UserMapper.xml放在config下mapper目录下。
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间,用于隔离sql -->
<!-- 还有一个很重要的作用,使用动态代理开发DAO,1. namespace必须和Mapper接口类路径一致 -->
<mapper namespace="com.mybatis.mapper.UserMapper">
	<!-- 根据用户id查询用户 -->
	<!-- 2. id必须和Mapper接口方法名一致 -->
	<!-- 3. parameterType必须和接口方法参数类型一致 -->
	<!-- 4. resultType必须和接口方法返回值类型一致 -->
	<select id="queryUserById" parameterType="int"
		resultType="com.mybatis.pojo.User">
		select * from user where id = #{id}
	</select>
	<!-- 根据用户名查询用户 -->
	<select id="queryUserByUsername" parameterType="string"
		resultType="com.mybatis.pojo.User">
		select * from user where username like '%${value}%'
	</select>
	<!-- 保存用户 -->
	<insert id="saveUser" parameterType="com.mybatis.pojo.User">
		<selectKey keyProperty="id" keyColumn="id" order="AFTER"
			resultType="int">
			select last_insert_id()
		</selectKey>
		insert into user(username,birthday,sex,address) values
		(#{username},#{birthday},#{sex},#{address});
	</insert>
</mapper>

1.3.3 UserMapper(接口文件)

public interface UserMapper {
	//根据id查询
	User queryUserById(int id);
	//根据用户名查询用户
	List<User> queryUserByUsername(String username);
	//保存用户
	void saveUser(User user);
}

1.3.4 加载UserMapper.xml文件

修改SqlMapConfig.xml文件,添加以下所示的内容:
在这里插入图片描述

1.3.5 测试

public class UserMapperTest {
	private SqlSessionFactory sqlSessionFactory;
	@Before
	public void init() throws Exception {
		// 创建SqlSessionFactoryBuilder
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		// 加载SqlMapConfig.xml配置文件
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
		// 创建SqlsessionFactory
		this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
	}
	@Test
	public void testQueryUserById() {
		// 获取sqlSession,和spring整合后由spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 从sqlSession中获取Mapper接口的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 执行查询方法
		User user = userMapper.queryUserById(1);
		System.out.println(user);
		// 和spring整合后由spring管理
		sqlSession.close();
	}
	@Test
	public void testQueryUserByUsername() {
		// 获取sqlSession,和spring整合后由spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 从sqlSession中获取Mapper接口的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 执行查询方法
		List<User> list = userMapper.queryUserByUsername("张");
		for (User user : list) {
			System.out.println(user);
		}
		// 和spring整合后由spring管理
		sqlSession.close();
	}
	@Test
	public void testSaveUser() {
		// 获取sqlSession,和spring整合后由spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 从sqlSession中获取Mapper接口的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 创建保存对象
		User user = new User();
		user.setUsername("刘备");
		user.setBirthday(new Date());
		user.setSex("1");
		user.setAddress("蜀国");
		// 执行查询方法
		userMapper.saveUser(user);
		System.out.println(user);
		// 和spring整合后由spring管理
		sqlSession.commit();
		sqlSession.close();
	}
}

1.3.6 小结

selectOne和selectList
    动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
namespace
    mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

二、SqlMapConfig.xml配置文件

2.1 配置内容

SqlMapConfig.xml中配置的内容和顺序如下:
  properties(属性)
  settings(全局配置参数)
  typeAliases(类型别名)
  typeHandlers(类型处理器)
  objectFactory(对象工厂)
  plugins(插件)
  environments(环境集合属性对象)
    environment(环境子属性对象)
      transactionManager(事务管理)
      dataSource(数据源)
  mappers(映射器)

2.2 properties(属性)

SqlMapConfig.xml可以引用java属性文件中的配置信息如下:
在这里插入图片描述SqlMapConfig.xml引用如下:
在这里插入图片描述在这里插入图片描述注意: MyBatis 将按照下面的顺序来加载属性:
    在 properties 元素体内定义的属性首先被读取。
    然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。

2.3 typeAliases(类型别名)

在这里插入图片描述在这里插入图片描述

2.4 mappers(映射器)

Mapper配置的几种方法:

2.4.1 <mapper resource=" " />

使用相对于类路径的资源(现在的使用方式)
如:<mapper resource=“sqlmap/User.xml” />

2.4.2 <mapper class=" " />

使用mapper接口类路径
如:<mapper class=“com.mybatis.mapper.UserMapper”/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

2.4.3 <package name=""/>

注册指定包下的所有mapper接口
如:<package name=“com.mybatis.mapper”/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

三、输入映射和输出映射

     Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。

3.1 parameterType(输入类型)

3.1.1 传递简单类型

使用#{}占位符,或者${}进行sql拼接。

3.1.2 传递pojo对象

Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。

3.1.3 传递pojo包装对象

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

3.1.3.1 编写QueryVo

在这里插入图片描述

3.1.3.2 Mapper.xml文件

在UserMapper.xml中配置sql,如下图。
在这里插入图片描述

3.1.3.3 Mapper接口

在UserMapper接口中添加方法,如下图
在这里插入图片描述

3.1.3.4 测试方法

在UserMapeprTest增加测试方法,如下:

	@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();
	}
3.1.3.5 效果

在这里插入图片描述

3.2 resultType(输出类型)

3.2.1 输出简单类型

3.2.1.1 Mapper.xml文件

在这里插入图片描述

3.2.1.2 Mapper接口

在这里插入图片描述

3.2.1.3 测试
	@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();
	}

3.2.2 输出pojo对象

参考mybatis的基础入门

3.2.3 输出pojo列表

参考mybatis的基础入门

3.3 resultMap

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

3.3.1 声明pojo对象

public class Order {
	// 订单id
	private int id;
	// 用户id
	private Integer userId;
	// 订单号
	private String number;
	// 订单创建时间
	private Date createtime;
	// 备注
	private String note;
	get/set方法......
}

3.3.2 Mapper.xml文件

在这里插入图片描述

3.3.3 Mapper接口

在这里插入图片描述

3.3.4 测试

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);
		}
	}

}

3.3.5 效果

在这里插入图片描述

3.3.6 使用resultMap

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

3.3.7 使用resultMap结果展示

在这里插入图片描述

四、动态sql

4.1 If标签

在这里插入图片描述

4.2 Where标签

在这里插入图片描述

4.3 Sql片段

Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
在这里插入图片描述如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace。
在这里插入图片描述

4.4 foreach标签

向sql传递数组或List,mybatis使用foreach解析,如下:根据多个id查询用户信息。
在这里插入图片描述在这里插入图片描述在这里插入图片描述

五、关联查询

5.1 商品订单数据模型

在这里插入图片描述

5.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

5.2.1 使用resultType

      使用resultType,改造订单pojo类,此pojo类中包括了订单信息和用户信息,这样返回对象的时候,mybatis自动把用户信息也注入进来了

5.2.1.1 改造pojo类

在这里插入图片描述

5.2.1.2 Mapper.xml

在这里插入图片描述

5.2.1.3 Mapper接口

在这里插入图片描述

5.2.1.4 测试

在这里插入图片描述

5.2.1.5 总结

定义专门的pojo类作为输出类型,其中定义了sql查询结果集所有的字段。此方法较为简单,企业中使用普遍

5.2.2 使用resultMap

使用resultMap,定义专门的resultMap用于映射一对一查询结果

5.2.2.1 改造pojo类

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

5.2.2.2 Mapper.xml
	<resultMap type="order" id="orderUserResultMap">
		<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 :配置一对一属性 -->
		<!-- 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>
	</resultMap>
	
	<!-- 一对一关联,查询订单,订单内部包含用户属性 -->
	<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
		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
	</select>
5.2.2.3 Mapper接口

在这里插入图片描述

5.2.2.4 测试

在这里插入图片描述

5.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

5.3.1 改造pojo类

在这里插入图片描述

5.3.2 Mapper.xml

	<resultMap type="user" id="userOrderResultMap">
		<id property="id" column="id" />
		<result property="username" column="username" />
		<result property="birthday" column="birthday" />
		<result property="sex" column="sex" />
		<result property="address" column="address" />
	
		<!-- 配置一对多的关系 -->
		<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>
	</resultMap>
	
	<!-- 一对多关联,查询订单同时查询该用户下的订单 -->
	<select id="queryUserOrder" resultMap="userOrderResultMap">
		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
	</select>

5.3.3 Mapper接口

在这里插入图片描述

5.3.4 测试

### 5.3.5 效果

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值