欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Mybatis框架_day01

程序员文章站 2024-03-14 19:58:59
...

学习笔记,把笔记放在本地,没有电脑时就没办法了,找个博客放笔记。

1. 什么是mybatis

  • mybatis是一个持久层的框架,是Apache下的*项目。
  • mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,*灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
  • mybatis可以将preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象(输出映射

2. Mybatis框架

Mybatis框架_day01

3. 入门程序

3.1. 需求

  • 根据用户id(主键)查询用户信息
  • 根据用户名称模糊查询用户信息
  • 添加用户
  • 删除用户
  • 更新用户

3.2. Mybatis运行环境

  1. 导入mybatis3.2.7jar核心包

  2. lib下,依赖包

  3. log4j.properties

  4. 数据库驱动包

  5. SqlMapConfig.xml

    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	<!-- 和spring整合后environments配置将废除 -->
    	<environments default="development">
    		<environment id="development">
    			<!-- 使用jdbc事务管理 -->
    			<transactionManager type="JDBC">
    				<!-- 数据库连接池 -->
    				<dataSource type="POOLED">
    					<property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
    					<property name="url" value="jdbc:sqlserver://localhost:1433;database=mybatis_day01" />
    					<property name="username" value="sa" />
    					<property name="password" value="123456" />
    				</dataSource>
    			</transactionManager>
    		</environment>
    	</environments>
    </configuration>
    

3.3. 根据用户id(主键)查询用户信息

3.3.1. 创建po类

public class User {

	//属性名和数据库表的字段对应
	private int id;
	private String username;
	private String sex;
	private Date birthday;
	private String address;

3.3.2. 映射文件

  • 映射文件名称:

    • User.xml,mapper代理开发映射文件名称加XXXMapper.xml,比如:UserMapper.xml、itemsMapper.xml
  • 在映射文件中配置sql语句

    <?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进行分类化管理,理解sql隔离
    注意:使用mapper代理方法开发,namespace有特殊重要作用
    -->
    <mapper namespace="test">
    	<!-- 在映射文件中配置很多sql语句 -->
    	<!--
    	通过select执行数据库查询
    	id:用于表示映射文件中的sql
    	将sql语句封装到mapperstatement对象中,所以将id成为statement的id
    	parameterType:指定输入参数类型,这里指定int型
    	#{}表示一个占位符
    	#{id}:其中id表示接收输入的参数,参数名称为id,如果输入参数是简单类型,#{}中的参数名可以任意,可以是value或其他名称
    	resultType:输出结果所映射的java对象类型,select执行resultType表示将单条记录所映射成的java对象
    	-->
    	<select id="findUserBuId" parameterType="int" resultType="cn.itcast.mybatis.po.User">
    		SELECT * FROM t_user WHERE id = #{id}
    	</select>
    </mapper>
    
  • 在sqlMapConfig.xml加载映射文件

     <!-- 加载映射文件 -->
     <mappers>
     	<mapper resource="sqlmap/User.xml"/>
     </mappers>
    

3.3.3. 写测试代码

	//mybatis配置文件
	String resource = "SqlMapConfig.xml";
	//得到配置文件流
	InputStream inputStream = Resources.getResourceAsStream(resource);
		
	//创建会话工厂,传入mybatis的配置文件信息
	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			
	//通过会话工厂得到sqlsession
	SqlSession sqlSession = sqlSessionFactory.openSession();
			
	//通过sqlsession操作数据库
	//第一个参数:映射文件中statement的id,等于namespace+"."+statement的id
	//指定和映射文件中管所匹配的parameterType类型的参数
	//最终结果是与映射文件中所匹配的resultType类型的对象
	User user = sqlSession.selectOne("test.findUserById",1);
		
	System.out.println(user);

3.4. 根据用户名称模糊查询用户信息

3.4.1 映射文件

  • 使用User.xml

       <!-- 根据用户名称模糊查询用户信息,可返回多条
        	 resultType指定的就是将单条记录所映射成的java对象类型
        	 ${}:表示拼接sql语句,将接收到参数的内容不加任何修饰拼接在sql中
        	 使用${}拼接sql,引起sql注入
        	 ${value}:接收输入参数的内容,如果传入类型是简单类型,${}中是能使用value
        	  -->
        	 <select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
        	 	SELECT * FROM t_user WHERE username LIKE '%${value}%'
        	 </select>
    

3.4.2 程序代码

List<User> list = sqlSession.selectList("test.findUserByName", "赵");

3.5. 添加用户

3.5.1 映射文件

  • 在User.xml文件中配置添加用户的Statement

    <!-- 添加用户
    	parameterType:指定输入参数类型是pojo(包括用户信息)
    	#{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值 -->
    <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
    	INSERT INTO t_user(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
    </insert>
    

3.5.2. 程序代码

//插入用户对象
User user = new User();
user.setUsername("王小军");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("中国");
		
sqlSession.insert("test.insertUser", user);
		
//提交事务
sqlSession.commit();

3.5.3. 自增主键的返回

  • 在MySQL中使用函数SELECT LAST_INSERT_ID();在SQLServer中可用其函数SELECT SCOPE_IDENTITY()

  • MySQL中可用

    <!-- 将插入的主键返回,返回到user对象中
    	SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用于自增主键
    	keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性
    	order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说
    	resultType:指定SELECT LAST_INSERT_ID()的结果类型 -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
    	SELECT LAST_INSERT_ID()
    </selectKey>
    
  • SQLServer中用

    <!-- 方法一 -->
    <!-- keyProperty 是实体里面的属性,如果传入是map就是map里的属性,
    	keyColumn是表上的主键名称 -->
    <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
    	INSERT INTO t_user(username,birthday,sex,address)
    	VALUES (#{username},#{birthday},#{sex},#{address})
    	SELECT SCOPE_IDENTITY()
    </insert>
    <!-- 方法二 -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
    	SELECT @@IDENTITY
    </selectKey>
    

3.5.4. 非自增主键的返回(使用uuid())

3.6. 删除用户

3.6.1. 映射文件

<!-- 根据id删除 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
    DELETE FROM t_user WHERE id=#{id}
 </delete>

3.6.2. 代码实现

//传入id删除用户
sqlSession.delete("test.deleteUser", 8);

3.7. 更新用户

3.7.1. 映射文件

<!-- 更新用户
   需要传入用户id
   需要传入用户更新信息
   parameterType指定user对象,包括id和更新信息,注意:id必须存在
   #{id}:从输入的user对象中获取id属性值 -->
<update id="updateUser" parameterType="cn.itcast.mybatis.po.User">
   update t_user set username=#{username},birthday=#{birthday},sex=#{sex},address={address} where id=#{id}
</update>

3.7.2. 代码实现

//更新用户对象
User user = new User();
user.setId(15);
user.setUsername("王大小");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("中国");
		
//传入id删除用户
sqlSession.update("test.updateUser", user);

3.8. 总结

3.8.1. parameterType

  • 在映射文件中通过parameterType指定输入参数的类型

3.8.2. resultType

  • 在映射文件中通过resultType指定输出结果的类型

3.8.3. #{}和${}

  • #{}表示一个占位符。
    • #{}接收输入参数,类型可以是简单类型,pojo,hashmap。如果接收的是简单类型。
    • #{}中可以写成value或其他名称。
    • #{}接收pojo对象值,通过OGNL解析对象中的属性值,通过属性.属性.属性…
  • ${}表示一个拼接符号,会引起sql注入,不建议使用
    • ${}接收输入参数,类型可以是简单类型,pojo,hashmap。如果接收的是简单类型。
    • 如果接收简单类型,只能写成vlaue。
    • ${}接收pojo对象值,通过OGNL解析对象中的属性值,通过属性.属性.属性…

3.8.4. selectOne和selectList

  • selectOne表示查询出一条记录进行映射,如果使用selectOne可以实现,使用selectList也可以实现(list中只有一个记录)
  • selectList表示查询吃一个列表(多条记录)进行映射,不可以使用selectOne实现

3.9. Mybatis和Hibernate本质区别和应用场景

3.9.1. Hibernate

  • 是一个标准的ORM框架(对象关系映射)。入门门槛高,不需要程序员写sql,sql语句自动生成。对sql语句进行优化、修改比较困难。
  • 应用场景:适用于需求变化不多的中小型项目,比如:后台管理系统,erp,orm,oa。

3.9.2. Mybatis

  • 专注是sql本身,需要程序员写sql语句,sql修改、有话比较方便。mybatis是一个不完全的ORM框架,虽然程序员自己写sql,mybatis也可以实现映射(输入映射、输出映射)。
  • 应用场景:适用于需求变化较多的项目,比如:互联网项目。

4. Mybatis开发dao的方法

4.1. sqlSession适用范围

4.1.1. SqlSessionFactoryBuilder

  • 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory
  • 将SqlSessionFactoryBuilder当成工具类即可,不需要使用单例管理SqlSessionFactoryBuilder
  • 在需要创建SqlSessionFactory时,只需要new一次SqlSessionFactoryBuilder即可

4.1.2. SqlSessionFactory

  • 通过SqlSessionFactory创建Sqlsession,使用单例模式管理SQLSessionFactory(工厂一旦创建,使用一个实例)
  • 将来mybatis和spring整合之后,使用单例模式管理SQLSessionFactory

4.1.3. SqlSession

  • SqlSession是一个面向用户(程序员)的接口
  • SqlSession中提供了很多操作数据库的方法,如:selectOne(返回单个对象)、selectList(返回单个或多个对象)
  • SqlSession是线程不安全的,在SqlSession实现勒种,除了有接口中的方法(操作数据库的方法)还有数据域属性。
  • SqlSession最佳应用场合在方法体内,定义成局部变量使用。

4.2. 原始dao开发方法(程序员需要些dao接口和dao实现类)

4.2.1. 思路

  • 需要向dao实现类中注入会话工厂SqlSessionFactory,在方法体内通过工厂创建SqlSession

4.2.2. Dao接口

public interface UserDao {

	//根据id查询用户信息
	public User findUserById(int id) throws Exception;

	//添加用户信息
	public void inserUser(User user) throws Exception;

	//删除用户信息
	public void deleteUser(int id) throws Exception;
}

4.2.3. Dao实现类

public class UserDaoImpl implements UserDao{

	//需要向dao实现类中注入SqlSessionFactory
	//通过构造方法注入
	private SqlSessionFactory sqlSessionFactory = null;
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
		this.sqlSessionFactory = sqlSessionFactory;
	}

	@Override
	public User findUserById(int id) throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		User user = sqlSession.selectOne("test.findUserById",id);
		//释放资源
		sqlSession.close();
		return user;
	}

	@Override
	public void inserUser(User user) throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		sqlSession.insert("test.insertUser", user);
		//执行事务
		sqlSession.commit();
		//释放资源
		sqlSession.close();
	}

	@Override
	public void deleteUser(int id) throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		sqlSession.delete("test.deleteUser", id);
		//执行事务
		sqlSession.commit();
		//释放资源
		sqlSession.close();
	}

}

4.2.4. 测试代码

public class UserDaoImplTest {

	private SqlSessionFactory sqlSessionFactory;
	//此方法是在执行testFindUserById之前执行
	@Before
	public void setUp() throws Exception {
		//创建SQLSessionFactory

		//mybatis配置文件
		String resource = "SqlMapConfig.xml";
		//得到配置文件流
		InputStream inputStream = Resources.getResourceAsStream(resource);

		//创建会话工厂,传入mybatis的配置文件信息
		sqlSessionFactory = new SqlSessionFactoryBuilder()
				.build(inputStream);
	}

	@Test
	public void testFindUserById() throws Exception {
		//创建userDao对象
		UserDao userDao = new UserDaoImpl(sqlSessionFactory);
		//调用UserDao方法
		User user = userDao.findUserById(1);

		System.out.println(user);
	}

}

4.2.5. 总结原始dao开发问题

  • dao接口实现类方法中讯在大量模板方法
  • 嗲用sqlsession方法是将statement的id硬编码了
  • 调用sqlsession方法是传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误在编译阶段也不报错

4.3. mapper代理方法(程序员只需要写mapper接口(相当于dao接口))

4.3.1. 思路(mapper代理开发规范)

  • 写mapper.xml映射文件

  • 写mapper接口需遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象

  • 开发规范:

    • 在mapper.xml中mapper的namespace等于mapper.java接口的地址

      <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离
      	注意:使用mapper代理方法开发,namespace有特殊重要作用 -->
      <mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
      
    • mapper.java接口中的方法名和mapper.xml中statement的id一致

    • mapper.java接口中方法的参数类型和mapper.xml中statement的parameterType指定的类型一致

    • mapper.java接口中的方法返回累心个mapper.xml中resultType指定的类型一致

      //根据id查询用户信息
      public User findUserById(int id) throws Exception;
      
  • 总结:以上开发规范主要是对下面的代码进行统一生成:

    • User user = sqlSession.selectOne("test.findUserById",id);
    • sqlSession.insert("test.insertUser", user);
    • sqlSession.delete("test.deleteUser", id);

4.3.2. mapper.java

public interface UserMapper {

	//根据id查询用户信息
	public User findUserById(int id) throws Exception;

	//根据用户名查询用户列表
	//
	public List<User> fingUserByName(String name) throws Exception;

	//插入用户
	public void insertUser(User user) throws Exception;

	//删除用户
	public void deleteUser(int id) throws Exception;

}

4.3.3. mapper.xml

4.3.4. 在SqlMapperConfig.xml中加载mapper.xml

<mapper resource="mapper/UserMapper.xml"/>

4.3.5. 测试代码

@Test
public void testFindUserById() throws Exception {
	
	SqlSession sqlSession = sqlSessionFactory.openSession();
	//创建UserMapper对象,mybatis自动生成mapper对象
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	
	User user = userMapper.findUserById(1);
	
	System.out.println(user);
}

4.3.6. 一些问题总结

4.3.6.1. 代理对象内部调用selectOne或selectList
  • 如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库.
  • 如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库.
4.3.6.2. mapper接口方法参数只能有一个
  • mapper接口方法参数只能有一个,是否不利于扩展维护。
  • 在系统框架中,dao层的代码是被业务层公用的,即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求
  • 注意:持久层中方法的参数可以用包装类型,map…,service方法中建议不要使用包装类型(不利于业务层的可扩展)

5. SqlMapConfig.xml

mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:

<properties> 用来加载属性文件
<settings> 用来设置全局参数
<typeAliases> 用来设置类型的别名
<typeHandlers> 用来设置类型处理器
<objectFactory> 用来设置对象工厂
<plugins> 用来设置插件
<environments> 用来设置mybatis的环境
<mappers> 用来配置映射文件

5.1. properties属性

5.1.1 需求

  • 将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties属性值

  • 在SqlMapConfig.xml中就不需要对数据库连接参数硬编码

  • 将数据库连接参数值配置在db.properties

    <!-- 加载属性文件 -->
    <properties resource="db.properties"></properties>
    <!-- 和spring整合后environments配置将废除 -->
    <environments default="development">
    	<environment id="development">
    		<!-- 使用jdbc事务管理 -->
    		<transactionManager type="JDBC" />
    		<!-- 数据库连接池 -->
    		<dataSource type="POOLED">
    			<property name="driver" value="${jdbc.driver}" />
    			<property name="url" value="${jdbc.url}" />
    			<property name="username" value="${jdbc.username}" />
    			<property name="password" value="${jdbc.password}" />
    		</dataSource>
    	</environment>
    </environments>
    

5.1.2. properties特性:

  • 注意:Mybatis将按照下面的顺序来加载属性:
    • 在properties元素体内定义的属性首先被读取
    • 然后会读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性
    • 最后读取parameterType传递的属性,它会覆盖已读取的同名属性

5.1.3. 建议:

  • 不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中
  • 在properties文件中定义属性名要有一定的特殊性,比如:xxxx.xxxx

5.2. settings全局参数配置

  • mybatis框架在运行时可以调整一些运行参数,比如开启二级缓存,开启延迟加载

5.3. typeAliases别名定义(重点)

5.3.1. 需求

  • 在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型,需要resultType执行输出结果的映射类型
  • 如果在指定类型是输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发

5.3.2. mybatis默认支持别名

Mybatis框架_day01

5.3.3. 自定义别名

5.3.3.1. 别名定义
<!-- 别名定义 -->
<typeAliases>
	<!-- 针对单个别名的定义
		type:类型的路径
		alias:别名
	 -->
	<typeAlias type="cn.itcast.mybatis.po.User" alias="user"/>
</typeAliases>
  • 引用别名

    <select id="findUserById" parameterType="int" resultType="user">
    	SELECT * FROM t_user WHERE id = #{id}
    </select>
    
5.3.3.2. 批量定义(常用)
<!-- 批量别名定义
	指定包名:mybatis自动扫描包中的po类,
	自动定义别名,别名就是类名(首字母大写或小写都可以)
 -->
<package name="cn.itcast.mybatis.po"/>

5.4. typeHandler类型处理器

  • mybatis中通过typeHandler完成jdbc类型和java类型的转换
  • 通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义

5.5. mapper映射配置

5.5.1. 通过resource方法一次加载单个映射文件

<!-- 通过resource方法一次加载一个映射文件 -->
<mapper resource="mapper/UserMapper.xml"/>

5.5.2. 通过mapper接口加载

<!-- 通过mapper接口加载映射文件
遵循一些规范:需要将mapper接口的类名和mapper.xml映射文件名称保持一致,且在一个目录中
上边规范前提是:使用的是mapper代理的方法
 -->
<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
  • 按照上面的规范,需将mapper.java和mapper.xml放在同一个文件中

5.5.3. 批量加载多个mapper(推荐使用)

<!-- 批量加载mapper
mapper接口的报名,mybatis在自动扫描包下边所有mapper接口进行加载
遵循一些规范:需要将mapper接口的类名和mapper.xml映射文件名称保持一致,且在一个目录中
上边规范前提是:使用的是mapper代理的方法
 -->
<package name="cn.itcast.mybatis.mapper"/>

6. 输入映射

  • 通过parameterType指定输入参数类型,可以是简单类型,HashMap,pojo的包装类型

6.1. 传递pojo的包装对象

6.1.1 需求

  • 完成用户信息的综合查询,需要传入很多查询条件(可能包括童虎信息、其他信息,比如商品、订单的)

6.1.2. pojo包装类型

  • 针对上边需求,建议使用自定义的包装类型的pojo

  • 在包装类型的pojo中将复杂的查询条件包装进去

     public class UserQueryVo {
     
     		//在这里包装所需要的查询条件
    
     		//用户查询条件
     		private UserCustom userCustom;
     	
     		public UserCustom getUserCustom() {
     			return userCustom;
     		}
     	
     		public void setUserCustom(UserCustom userCustom) {
     			this.userCustom = userCustom;
     		}
     		
     		//可以包装其他的查询条件,比如订单,商品
     		//...
    

6.1.3. mapper.xml

  • 在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂查询)。

    <!-- 用户信息综合查询
    	#{userCustom.sex}:取出pojo包装对象中性别值
    	${userCusotm.username}:取出pojo包装对象中用户姓名 -->
    <select id="findUserList" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="cn.itcast.mybatis.po.UserCustom">
    	SELECT *
    	FROM t_user where user.sex=#{userCustom.sex} and user.username like '%${userCusotm.username}%'
    </select>
    

6.1.4. mapper.java

//用户信息综合查询
public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;

6.1.5. 测试代码

public void testFindUserList() throws Exception {

	SqlSession sqlSession = sqlSessionFactory.openSession();
	//创建UserMapper对象,mybatis自动生成mapper对象
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	
	//创建包装对象,设置查询条件
	UserQueryVo userQueryVo = new UserQueryVo();
	UserCustom userCustom = new UserCustom();
	userCustom.setSex("男");
	userCustom.setUsername("赵");
	userQueryVo.setUserCustom(userCustom);
	//调用userMapper的方法
	List<UserCustom> list = userMapper.findUserList(userQueryVo);
	
	System.out.println(list);
}

7. 输出映射

7.1. resultType

  • 使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功
  • 如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象
  • 只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象

7.1.1. 输出简单类型

7.1.1.1. 需求
  • 用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页
7.1.1.2. mapper.xml
<!-- 用户信息综合查询总数
parameterType:指定输入类型和发ingUserList一样
 -->
<select id="findUserCount" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="int">
	SELECT COUNT(*) FROM t_user where sex=#{userCustom.sex} and username like '%${userCustom.username}%'
</select>
7.1.1.3. mapper.java
//用户信息综合查询总数
public int findUserCount(UserQueryVo userQueryVo) throws Exception;
7.1.1.4. 测试代码
public void testFindUserCount() throws Exception {

	SqlSession sqlSession = sqlSessionFactory.openSession();
	//创建UserMapper对象,mybatis自动生成mapper对象
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	
	//创建包装对象,设置查询条件
	UserQueryVo userQueryVo = new UserQueryVo();
	UserCustom userCustom = new UserCustom();
	userCustom.setSex("男");
	userCustom.setUsername("赵");
	userQueryVo.setUserCustom(userCustom);
	//调用userMapper的方法
	int count = userMapper.findUserCount(userQueryVo);
	
	System.out.println(count);
}
7.1.1.5. 小结
  • 查询出来的结果集是一行且一列,可以使用简单类型进行输出映射

7.1.2. 输出pojo对象和pojo对象列表

  • 不管输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的
  • 在mapper.java指定的方法返回值类型不一样:
    • 输出单个pojo对象,方法返回值是单个对象类型
    • 输出pojo对象列表,方法返回值是List
  • 生成的动态代理对象中是根据mapper方法的返回值类型确定调用selectOne还是selectList

7.2. resultMap

  • mybatis中可以使用resultMap完成高级输出结果映射

7.2.1. resultMap使用方法

  • 如果查询出来的列名和pojo属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做映射关系
  • 第一步 定义resultMap
  • 第二步 使用resultMap作为statement的输出映射类型

7.2.2 需求:将下边的sql使用User完成映射

SELECT id id_,username username_ FROM t_user where id=#{value}
  • User类中属性名和上边查询列名不一致
7.2.2.1. 定义resultMap
<!-- 定义resultMap
将SELECT id id_,username username_ FROM t_user和User类中的属性做一个映射关系
type:resultMap最终所映射的java对象类型,可以使用别名
id:对resultMap的唯一标识
 -->
 <resultMap type="user" id="userResultMap">
	<!-- id标识查询结果集中唯一标识
	 column:查询出来的列名
	 property:type指定的pojo类型中的属性名
	 最终resultMap对column和property做一个映射关系(对应关系)
	  -->
	 <id column="id_" property="id"/>
	 <!-- 
	 result对普通列的定义
	  -->
	  <result column="username_" property="username"/>
 </resultMap>
7.2.2.2. 使用resultMap作为statement的输出映射类型
<!-- 使用resultMap进行输出映射
resultMap:指定定义的resultMap的id,如果这个resultMap在其他的mapper文件中,前边应加namespace
 -->
<select id="findUserCount" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="userResultMap">
	SELECT id id_,username username_ FROM t_user where id=#{value}
</select>
7.2.2.3. mapper.java
//根据用户名查询用户列表
public List<User> fingUserByName(String name) throws Exception;
7.2.2.4. 测试
public void testFindUserByIdResultMap() throws Exception {

	SqlSession sqlSession = sqlSessionFactory.openSession();
	//创建UserMapper对象,mybatis自动生成mapper对象
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	
	//调用userMapper的方法
	User user = userMapper.findUserByIdResultMap(1);	
	
	System.out.println(user);
}

7.3. 小结

  • 使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功
  • 如果查询出来的列名和pojo属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做映射关系

8. 动态sql

8.1. 什么是动态sql

  • mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装

8.2. 需求

  • 用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql
  • 对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。

8.3. mapper.xml

<select id="findUserList" parameterType="cn.itcast.mybatis.po.UserQueryVo" 
  resultType="cn.itcast.mybatis.po.UserCustom">
	SELECT username,address,birthday FROM t_user
	<!-- where可以自动去掉条件中第一个and -->
	<where>
		<if test="userCustom!=null">
			<if test="userCustom.sex!=null and userCustom.sex!=''">
				and sex=#{userCustom.sex}
			</if>
			<if test="userCustom.username!=null and userCustom.username!=''">
				and username like '%${userCustom.username}%'
			</if>
		</if>
	</where>
</select>

8.4. 测试代码

//创建包装对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
//由于使用动态sql,不设置值,条件不会拼接在sql中
userCustom.setSex("男");
//userCustom.setUsername("赵");
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(null);

8.5. sql片段

8.5.1. 需求

  • 将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其他statement中就可以引用sql片段

8.5.2. 定义sql片段

<!-- 定义sql片段
id:sql片段唯一标识
经验:是基于单标定义sql片段,这样这个sql片段可重用性才高
在sql片段中不要包含where
-->
<sql id="query_user_where">
 	<if test="userCustom!=null">
		<if test="userCustom.sex!=null and userCustom.sex!=''">
			and sex=#{userCustom.sex}
		</if>
		<if test="userCustom.username!=null and userCustom.username!=''">
			and username like '%${userCustom.username}%'
		</if>
	</if>
</sql>

8.5.3. 引用sql片段

<select id="findUserList" parameterType="cn.itcast.mybatis.po.UserQueryVo" 
  resultType="cn.itcast.mybatis.po.UserCustom">
	SELECT username,address,birthday FROM t_user
	<!-- where可以自动去掉条件中第一个and -->
	<where>
		<!-- 引用sql片段的id,如果refid引用的片段不在本mapper中,需要加namespace -->
		<include refid="query_user_where"></include>
		<!-- 这里还可以引用其他的sql片段 -->
	</where>
</select>

8.6. foreach

  • 向sql传递数组或list,mybatis使用foreach解析

8.6.1. 需求

  • 在用户查询列表和查询总数的statement中,增加多个id的输入查询
  • sql语句如下:SELECT * FROM t_user WHERE id=1 or id=3 or id=4

8.6.2. 在输入参数类型中添加listids传入多个id

//传入多个id
private List<Integer> ids;

8.6.3. 修改mapper.xml

  • 在查询条件中,查询条件定义成了sql片段,需要修改sql片段

    <if test="ids!=null">
    	<!-- 使用foreach遍历传入ids
    		collection:指定输入对象中集合属性
    		item:每次遍历生成的变量名
    		open:开始便利是要拼接的串
    		close:结束遍历是拼接的串
    		separator:每遍历的两个对象中间需要拼接的串 -->
    	<!-- 实现下边的sql拼接
    		AND (id=1 OR id=3 OR id=4) -->
    	<foreach collection="ids" item="item_id" open="AND (" close=")" separator="OR">
    		<!-- 每个遍历需要拼接的串 -->
    		id=#{item_id}
    	</foreach>
    </if>
    

8.6.4. 测试代码

//传入多个id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(3);
ids.add(4);
userQueryVo.setIds(ids);
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);