Mybatis总结

Mybatis

  MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

  MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

  iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Mapping和Data Access Objects(DAOs)

ORM介绍

  对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示着额外的执行开销;然而,如果ORM作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在。 更重要的是用于控制转换的元数据需要提供和管理;但是同样,这些花费要比维护手写的方案要少;而且就算是遵守ODMG规范的对象数据库依然需要类级别的元数据。

持久化

​  持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。

持久层

​  持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联。

ORM

  即Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。(ORM框架的代表作:hibernate)

为什么要做持久化和ORM设计

  在目前的企业应用系统设计中,MVC,即 Model(模型)- View(视图)- Control(控制)为主要的系统架构模式。MVC 中的 Model 包含了复杂的业务逻辑和数据逻辑,以及数据存取机制(如 JDBC的连接、SQL生成和Statement创建、还有ResultSet结果集的读取等)等。将这些复杂的业务逻辑和数据逻辑分离,以将系统的紧耦 合关系转化为松耦合关系(即解耦合),是降低系统耦合度迫切要做的,也是持久化要做的工作。MVC 模式实现了架构上将表现层(即View)和数据处理层(即Model)分离的解耦合,而持久化的设计则实现了数据处理层内部的业务逻辑和数据逻辑分离的解耦合。 而 ORM 作为持久化设计中的最重要也最复杂的技术,也是目前业界热点技术。目的,解决持久化问题。

ORM框架

Hibernate

  全自动的ORM框架,不用书写SQL语句,就可以对数据库进行增删改查. "跨平台" .Hibernate的代码可以适用于多种数据库.但是,配置比较复杂,第二点查询效率相对而言较低,且不灵活.

Mybatis

  半自动的ORM框架,需要书写SQL语句,就可以对数据库进行增删查改.轻量级的ORM框架.

Mybatis入门

  中文文档:https://mybatis.org/mybatis-3/zh/index.html

mybatis使用步骤

1.引入mybatis核心jar包

mybatis-x.x.x.jar

2.配置mybatis核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybatis 核心配置文件 数据持久化层配置信息 -->
<!-- 配置 -->
<configuration>
    <!-- 运行环境
		default : 采用环境 -->
	<environments default="development">
        <!-- 具体的环境  id 具体环境唯一标识-->
		<environment id="development">
            <!-- 事务管理器 -->
			<transactionManager type="JDBC" />
            <!-- 数据源 -->
			<dataSource type="POOLED">
                <!-- 数据库连接驱动 -->
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://127.0.0.1:3306/0812_stmng" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>
	<!-- 映射文件  具体的映射器 -->
	<mappers>
		<mapper resource="UserMapper.xml" />
	</mappers>
</configuration>

3.orm映射文件

<?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">
 <!-- orm 映射文件  -->
<mapper namespace="com.sxt.pojo.User">
    <!-- 
		查询指令标签
		id : 查询指令的唯一标识	
		resultType : 查询结果映射的类 
	 -->
  	<select id="selectOne" resultType="com.sxt.pojo.User">
   		select id as id, user_name as userName,password as password,real_name as realName from user where id=1
  	</select>
</mapper>

4.进行持久化操作

package com.sxt.test;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.sxt.pojo.User;

public class Test {
	
	public static void main(String[] args) {
		// 1.加载配置文件
        // InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		InputStream in = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		// 2.解析配置文件  构建一个SqlSession 工厂
		SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
		// 根据SqlSession 工厂 获取SqlSession会话对象
		SqlSession sqlSession = sqlSessionFactory.openSession();
		// 3. 使用会话对象操作数据库     namespace + select 标签中的ID值
		User user = sqlSession.selectOne("com.sxt.pojo.User.selectOne");
		System.out.println(user);
        //4.释放资源
		session.close();
	}

}

Mybatis-CRUD 方式一

工具类:

package com.sxt.util;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * SqlSession 工具类
 */
public class MybatisUtil {
	
	private MybatisUtil() {}
	
	static final SqlSessionFactory sqlSessionFactory ;
	
	static {
		String source = "mybatis.xml";
		// 获取核心配置文件
		InputStream in = MybatisUtil.class.getClassLoader().getResourceAsStream(source);
		// 创建一个SqlSessionFactoryBuilder对象
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		// 构建一个SqlSessionFactory 工厂对象
		sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
	}
	
	/**
	 * 获取SqlSession
	 */
	public static SqlSession getSession() {
		return sqlSessionFactory.openSession();
	}
}

IUserDao

package com.sxt.dao;

import java.util.List;

import com.sxt.pojo.User;

public interface IUserDao {
	
	/**
	 * 根据ID查询用户
	 * @param id
	 * @return: User
	 */
	public User selectOne(Integer id);
	
	/**
	 * 查询所有用户
	 * @return: List<User>
	 */
	public List<User> selectAll();
	
	/**
	 * 新增一个用户
	 * @param user
	 * @return: int
	 */
	public int insert(User user);
	
	/**
	 * 修改用户
	 * @param user
	 * @return: int
	 */
	public int update(User user);
	
	/**
	 * 删除用户
	 * @param id
	 * @return: int
	 */
	public int delete(Integer id);

}

UserDaoImpl

package com.sxt.dao.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.sxt.dao.IUserDao;
import com.sxt.pojo.User;
import com.sxt.util.MybatisUtil;

public class UserDaoImpl implements IUserDao {

	@Override
	public User selectOne(Integer id) {
		SqlSession session = MybatisUtil.getSession();
		User user = session.selectOne("com.sxt.pojo.User.selectOne", id);
		System.out.println(user);
		session.close();
		return user;
	}

	@Override
	public List<User> selectAll() {
		SqlSession session = MybatisUtil.getSession();
		List<User> users = session.selectList("com.sxt.pojo.User.selectAll");
		System.out.println(users);
		session.close();
		return users;
	}

	@Override
	public int insert(User user) {
		SqlSession session = MybatisUtil.getSession();
		int m = session.insert("com.sxt.pojo.User.insert", user);
		session.commit();
		session.close();
		return m;
	}

	@Override
	public int update(User user) {
		SqlSession session = MybatisUtil.getSession();
		int m = session.insert("com.sxt.pojo.User.update", user);
		session.commit();
		session.close();
		return m;
	}

	@Override
	public int delete(Integer id) {
		SqlSession session = MybatisUtil.getSession();
		int m = session.insert("com.sxt.pojo.User.delete", id);
		session.commit();
		session.close();
		return m;
	}
	
	public static void main(String[] args) {
		UserDaoImpl userDao = new UserDaoImpl();
		//userDao.selectOne(1);
		//userDao.selectAll();
		User user = new User(7, "123123", "123", "7777");
		//userDao.insert(user);
		//userDao.update(user);
		userDao.delete(7);
		
	}
}

核心配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  <!-- mybatis 核心配置文件  数据持久化层配置信息 -->
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/0812_stmng"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 映射文件 -->
  <mappers>
    <mapper resource="UserMapper.xml"/>
  </mappers>
</configuration>

映射配置文件

<?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">
 <!-- orm 映射文件  -->
<mapper namespace="com.sxt.pojo.User">

  <select id="selectOne" resultType="com.sxt.pojo.User">
   	select id as id, user_name as userName,password as password,real_name as realName from user where id=#{id}
  </select>
  
  <select id="selectAll" resultType="com.sxt.pojo.User">
  	select id as id, user_name as userName,password as password,real_name as realName from user 
  </select>
  
  <insert id="insert">
  	insert into user (user_name,password,real_name) value(#{userName},#{password},#{realName}) 
  </insert>
  
  <update id="update">
  	update user set user_name = #{userName},password = #{password},real_name = #{realName} where id = #{id}
  </update>
  
  <delete id="delete">
  	delete from user where id = #{id}
  </delete>
  
</mapper>

Mybatis-CRUD 方式二

CRUD代码

核心配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  <!-- mybatis 核心配置文件  数据持久化层配置信息 -->
<configuration>

  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/0812_stmng"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 映射文件 -->
  <mappers>
    <mapper resource="UserMapper.xml"/>
  </mappers>
</configuration>

映射文件

<?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">
 <!-- orm 映射文件  -->
 <!-- 此时映射文件的 namespace的值是  mapper 接口的全路径 -->
<mapper namespace="com.sxt.mapper.IUserMapper">

  <select id="selectOne" resultType="com.sxt.pojo.User">
   	select id as id, user_name as userName,password as password,real_name as realName from user where id=#{id}
  </select>
  
  <select id="selectAll" resultType="com.sxt.pojo.User">
  	select id as id, user_name as userName,password as password,real_name as realName from user 
  </select>
  
  <insert id="insert">
  	insert into user (user_name,password,real_name) value(#{userName},#{password},#{realName}) 
  </insert>
  
  <update id="update">
  	update user set user_name = #{userName},password = #{password},real_name = #{realName} where id = #{id}
  </update>
  
  <delete id="delete">
  	delete from user where id = #{id}
  </delete>
  
</mapper>

mapper接口

package com.sxt.mapper;

import java.util.List;

import com.sxt.pojo.User;

public interface IUserMapper {
	
	/**
	 * 根据ID查询用户
	 * @param id
	 * @return: User
	 */
	public User selectOne(Integer id);
	
	/**
	 * 查询所有用户
	 * @return: List<User>
	 */
	public List<User> selectAll();
	
	/**
	 * 新增一个用户
	 * @param user
	 * @return: int
	 */
	public int insert(User user);
	
	/**
	 * 修改用户
	 * @param user
	 * @return: int
	 */
	public int update(User user);
	
	/**
	 * 删除用户
	 * @param id
	 * @return: int
	 */
	public int delete(Integer id);

}

测试类:

package com.sxt.test;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.sxt.mapper.IUserMapper;
import com.sxt.pojo.User;
import com.sxt.util.MybatisUtil;

public class Test {

	public static void main(String[] args) {
		SqlSession session = MybatisUtil.getSession();
		// 使用代理创建了mapper 的实现类:
		// 1. 对应的mapper映射文件中,namespace 一定要是对应的mapper接口的全路径
		// 2. 映射文件中,标签的ID值,一定要与接口中的方法名一致
		IUserMapper mapper = session.getMapper(IUserMapper.class);
		// 查询
		List<User> users = mapper.selectAll();
		
		User user = mapper.selectOne(1);
		
		mapper.insert(new User(0, "111", "111", "111"));
		mapper.update(new User(6, "111", "111", "111"));
		mapper.delete(6);
		System.out.println(user);
		
		System.out.println(mapper);
			
		session.commit();
		session.close();
	}
}

注意点:

  对应的mapper映射文件中,namespace 一定要是对应的mapper接口的全路径
  映射文件中,标签的ID值,一定要与接口中的方法名一致

异常信息

  1. namespace值与接口路径不一致

  1. 方法名和标签ID值不一致

mybatis核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  <!-- mybatis 核心配置文件  数据持久化层配置信息 -->
<configuration>

	<!-- 引入属性配置文件
		其他地方可以使用 ${key}的形式,使用属性配置文件的对应的值
	 -->	
	<properties resource="jdbc.properties"  />
	<!-- 全局设置 -->
	<settings>
		<!-- 开启二级缓存 -->
		<setting name="cacheEnabled" value="true "/>
		<!-- 配置日志   默认是自动查找 -->
		<setting name="logImpl" value="LOG4J"/>
	</settings>
	<!-- 配置类别名 -->
	<typeAliases>
		<!-- type : 表示具体的类    alias 类的别名  这种配置方式 是为每个具体的类指定别名 -->
		<!-- <typeAlias type="com.sxt.pojo.User" alias="zhangsan"/> -->
		<!-- name : 需要配制别名的类的包名  这种配置方式  默认类的别名就是类名  -->
		<package name="com.sxt.pojo" />
	</typeAliases>
	<!-- 插件 -->
	<!-- <plugins>
		分页插件
		<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
	</plugins> -->
	<!-- 
		environments : 环境配置  mybatis运行环境    default : 表示运行时使用的环境,例如 : 开发时一套运行环境   测试时使用测试库环境
			|== environment : 表示具体的环境   可以有多个
			|== transactionManager : 事务管理器 : JDBC  使用JDBC事务管理    MANAGED : 它从来不提交或回滚一个连接 
			|== dataSource :  	POOLED : 使用了内置连接池 
								UNPOOLED : 每次都新建和释放连接   无连接池  
							  	JNDI : 本地连接池   一般是在服务中配置连接池
				property : 数据库连接依赖属性					  	
	 -->
  <environments default="develop">
    <environment id="develop">
      <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>
    
    <environment id="test">
      <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>
  <!-- 映射文件  -->
  <!-- 
  	mapper:
  		resource : 配置映射文件的位置
  		url : 配置映射文件的位置  但是  url这种形式,配置的物理路径  不使用
  		class : 配置Mapper的全路径,但是使用这种配置方式,映射配置文件要与mapper类写在一起. 但是在实际开发中,src下面只写Java代码,不写xml配置信息
  	package :
  			配置所有mapper接口的包
   -->
  <mappers>
    <mapper resource="UserMapper.xml"/>
  </mappers>
</configuration>

映射文件

<?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 :
		1. 区分sql标签节点,不同命名空间,标签节点ID值可以相同
		2. 绑定映射器 Mapper,当使用动态代理的时候,namespace必须与Mapper接口全路径相同
		
	select  insert   update  delete   sql语义化标签
	cache : 开启缓存
	sql : sql片段
	resultMap : 结果集映射器	
	
	select标签中属性:
		id : 唯一标识
		resultMap : 结果映射器  配置 resultMap的ID
		parameterType : 参数类型   默认可缺省
		resultType : 查询结果类型
		timeout : 超时时间
		
	insert : 
		useGeneratedKeys : 是否使用自动生成主键值
		keyColumn : 自增涨的列名
		keyProperty : 自增长的列名对应属性名
		以上3个属性,只支持支持自增涨的数据库
 -->
<mapper namespace="com.sxt.mapper.IUserMapper">
	
 <!--  <select  id="selectOne" resultMap="BASE_RESULT_MAP" parameterType="" timeout="">
   	select id  user_name ,password as password,real_name as realName from user where id=#{id}
  </select>
  
  <select id="selectAll" resultType="com.sxt.pojo.User">
  	select id as id, user_name as userName,password as password,real_name as realName from user 
  </select> -->
  
  <insert id="insert" useGeneratedKeys="true"  keyColumn="id" keyProperty="id" >
  	insert into user (user_name,password,real_name) value(#{userName},#{password},#{realName}) 
  </insert>
  
<!--   <update id="update">
  	update user set user_name = #{userName},password = #{password},real_name = #{realName} where id = #{id}
  </update>
  
  <delete id="delete">
  	delete from user where id = #{id}
  </delete> -->
 
</mapper>

占位符:$和#

​  mybatis参数传递支持两种方式:${xxx} 和 #{xxx}

​  但是 #{xx}使用JDBC中防止SQL注入的一种方式,SQL语句会进行预编译;而${XX}形式,则是使用字符串拼接的形式,可能存在SQL攻击安全问题。

​  所以一般情况下,能使用#{xx}形式尽量使用#{}这种形式。如果,在某些特定的场景,如:需要动态查询表,动态查询库,动态查询字段时,需使用$ {}进行拼接。

模糊查询

方式一:使用$拼接

<select id="selectAll" parameterType="String"  resultType="Student">
	select `id`, `name`, `age`, `sex`, `phone`, `img` from student where name like '%${name}%'
</select>

方式二:concat函数和#{xxx} 【推荐】

<select id="selectAll2" parameterType="String"  resultType="Student">
  	select `id`, `name`, `age`, `sex`, `phone`, `img` from student where name like concat('%',#{name},'%');
</select>

方式三:bind标签取别名

<!-- 方式三 -->
<select id="selectAll3" parameterType="String"  resultType="Student">
  	<bind name="keywords" value="'%' + new String(name) + '%'  "/>
  	select `id`, `name`, `age`, `sex`, `phone`, `img` from student where name like #{keywords};
</select>

分页查询

方式一:使用原生的数据库分页

<!-- 原生分页 -->
<select id="selectPage1" parameterType="Integer"  resultType="Student">
  	select `id`, `name`, `age`, `sex`, `phone`, `img` from student limit #{page},#{limit}
</select>

注意点:

  当多个参数时,需要使用对象进行传递或者使用@Param注解,为参数取别名.否则不支持.

方式二:使用Mybatis提供RowBounds

RowBounds rowBounds = new RowBounds(0, 1);
public List<Student> selectPage2(RowBounds rowBounds);
<!-- mybatis分页 -->
<select id="selectPage2"   resultType="Student">
  	select `id`, `name`, `age`, `sex`, `phone`, `img` from student 
</select>

使用以上两种方式,只能获取到数据,其它关于分页的信息无法获取到.

方式三:插件分页:PageHelper

1.引入相关jar包:

pagehelper-5.1.10.jar
jsqlparser-2.1.jar

2.配置PageHelper分页插件

<!-- 配置插件 -->
<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

3.开启PageHelper分页


//开启分页 永远只对最近一次查询生效
//若下次查询也需要进行分页查询 需要重新开启
Page<Student> pageInfo = PageHelper.startPage(1, 10);
studentDao.selectPage("0");
System.out.println("当前页码:"+pageInfo.getPageNum());
System.out.println("最大页数"+pageInfo.getPages());
System.out.println("符合条件数据行数:"+pageInfo.getTotal());
System.out.println("每页数据行数:"+pageInfo.getPageSize());
System.out.println("查询具体数据:"+pageInfo.getResult());
for (Student student : pageInfo.getResult()) {
	System.out.println(student);
}
<select id="selectPage" parameterType="String" resultType="Student">
		select id,name,age,sex,phone from student where name like  concat('%',#{name},'%')
</select>

注意:

  PageHelper每次只对最近的一次分页有效,下次如果想进行分页查询,需要重新开启分页。

属性名和字段名不一致问题

​​  在mybatis中,当返回查询结果是ResultType时,Mybatis默认是根据查询结果的列名查找对应类的字段.然后利用反射进行值注入.如果列名和属性名称不一致,此时该值为null.

​ 解决这个问题(方案2种):

1.使用别名,使用as关键字,为表的列名取别名,与类中的属性名保持一致

2.ResultMap进行解析映射

<resultMap type="Student" id="BASE_RESULT_MAP">
	<!-- 表示该列是主键 -->
	<!-- 
		column : 查询结果的列名
		property : type指定的类中属性名
	  -->
	<id column="id" property="id" />
	<result column="stName" property="name"/>
	<result column="age" property="age"/>
	<result column="sex" property="sex"/>
	<result column="img" property="img"/>
	<result column="phone" property="phone"/>
</resultMap>  

<!-- 使用ResultMap -->
<select id="selectList2" resultMap="BASE_RESULT_MAP">
  	select `id`, `name` as stName, `age`, `sex`, `phone`, `img` from student 
</select>

sql片段

​  由于xml配置中,很多sql内容是重复,基于这一点,mybatis提供了sql标签,用于抽离重复公共的sql,然后使用inlud标签,进行引入.

<sql id="BASE_COLUMN">
		`id`, `name`, `age`, `sex`, `phone`, `img`
</sql>

<select id="selectList"   resultType="Student">
  	select 
  		<include refid="BASE_COLUMN" /> 
  	from student  where name like concat('%',#{name},'%')
</select>

动态SQL

  即根据不同的条件,动态的生成不同的SQL语句.Mybatis提供了:

    if、choose(when otherwise)、where、set、trim、foreach 等标签,实现动态SQL。

if 标签

  if标签是条件判断标签,即符合if标签中条件表达式: test 表达式,则会将if标签包裹的内容进行拼接

<!-- 根据条件查询数据  -->
<select id="selectList" resultType="Student">
    
	select
		<include refid="BASE_COLUMN" />
	from student where 1=1
    
	<if test="id != null and id !=''">
		and id = #{id}
	</if>
	<if test="name != null and name !=''">
		and name like concat('%',#{name},'%')
	</if>
	<if test="minAge != null and minAge !=''">
		and age > #{minAge}
	</if>
	<if test="maxAge != null and maxAge !=''">
		and #{maxAge} >= age
	</if>
	<if test="sex != null and sex !=''">
		and sex = #{sex}
	</if>
</select>
public static void main(String[] args) {
	SqlSession session = MybatisUtil.getSession();

	StudentMapper studentMapper = session.getMapper(StudentMapper.class);

	Map<String, Object> param = new HashMap<String, Object>();
	// param.put("id", 1);
	param.put("name", "韩");
	param.put("minAge", 15);
	param.put("maxAge", 28);
	param.put("sex", "女");
	Page<Object> pageInfo = PageHelper.startPage(1, 5);
	List<Student> students = studentMapper.selectList(param);
	System.out.println(students);
	session.close();
}

choose(when otherwise)

  多条件分支,只会满足choose中最上面when,满足后,拼接sql,若其他when中的表达式不会处理.若都不满足则会执行otherwise.

<select id="selectList2" resultType="Student">
	select
		<include refid="BASE_COLUMN" />
	from student where 1=1
    
	<choose>
		<when test="age > 18">
			and #{age} > 28
		</when>
		<when test="age > 10">
			and #{age} > 20
		</when>
		<when test="age > 5">
			and #{age} > 15
		</when>
		<otherwise>
			and #{age} > 0
		</otherwise>
	</choose>
</select>
public static void main(String[] args) {
	SqlSession session = MybatisUtil.getSession();
	
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	
	List<Student> students = studentMapper.selectList2(4);
	System.out.println(students);
	
	session.close();
}

where标签

​​  where标签,用于取代sql语句中where,由于动态sql中,不知道实际运行时,具体满足的那个条件,所以一般在where进行sql处理.为此mybatis提供了where。当所有条件都不满足时,不会拼接where 字符串,若存在任意的条件满足,则自动拼接where字符串,且会将第一个and 去除。

<!-- where示例 -->
<select id="selectList3" resultType="Student">
	select
		<include refid="BASE_COLUMN" />
	from student
	<where>
		<if test="id != null and id !=''">
			and id = #{id}
		</if>
		<if test="name != null and name !=''">
			and name like concat('%',#{name},'%')
		</if>
		<if test="minAge != null and minAge !=''">
			and age > #{minAge}
		</if>
		<if test="maxAge != null and maxAge !=''">
			and #{maxAge} >= age
		</if>
		<if test="sex != null and sex !=''">
			and sex = #{sex}
		</if>
	</where>
</select>
public static void main(String[] args) {
	SqlSession session = MybatisUtil.getSession();
	
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	Map<String,Object> param = new HashMap<String, Object>();
	param.put("id", 1);
	param.put("name", "韩");
	List<Student> students = studentMapper.selectList3(param);
	System.out.println(students);
	
	session.close();
}

set标签

  set标签就是用于取代,sql语句中set字符。在set使用if,若set中不存在满足条件的if时,不会拼接set,且set会将最后的一个逗号去除。

<!-- set标签 -->
<update id="updateById" >
	update student  
	<set>
		<if test="name != null and name !=''">
			name = #{name},
		</if>
		<if test="age != null and age !=''">
			age = #{age},
		</if>
		<if test="sex != null and sex !=''">
			sex = #{sex},
		</if>
	</set>
	where id = #{id}
</update>
public static void main(String[] args) {
	SqlSession session = MybatisUtil.getSession();
	
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	Student st = new Student();
	st.setId(1);
	st.setName("韩梅梅呀");
	st.setAge(18);
	st.setSex("MM");
	studentMapper.updateById(st);
	
	session.commit();
	session.close();
}

trim标签

  使用trim标签可以取代where和set标签

<!-- trim标签 -->
<select id="selectList4" resultType="Student">
	select
		<include refid="BASE_COLUMN" />
	from student 
	<!-- 
		prefix : 新增一个前缀
		prefixOverrides : 去除第一个指定的字符
		suffix : 新增一个后缀
		suffixOverrides : 去除最后一个指定字符
	 -->
	<trim prefix="where"  prefixOverrides="and|or" suffix="and 1=1" suffixOverrides=","> 
		<if test="id != null and id !=''">
			or id = #{id},
		</if>
		<if test="name != null and name !=''">
			and name like concat('%',#{name},'%')
		</if>
		<if test="minAge != null and minAge !=''">
			and age > #{minAge}
		</if>
		<if test="maxAge != null and maxAge !=''">
			and #{maxAge} >= age
		</if>
		<if test="sex != null and sex !=''">
			and sex = #{sex}
		</if>
	</trim>
</select>
public static void main(String[] args) {
	SqlSession session = MybatisUtil.getSession();
	
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	Map<String,Object> params = new HashMap<String, Object>();
	params.put("id", 1);
	studentMapper.selectList4(params);
	
	session.commit();
	session.close();
}

foreach循环标签

<!-- foreach 循环  -->
<select id="selectList5" resultType="Student">
	select
		<include refid="BASE_COLUMN" />
	from student 
	<!-- 
		collection : 被循环的集合
		item : 集合中的元素
		open : 开始循环前拼接的字符串
		close : 结束循环时拼接的字符串
		separator : 每次循环期间拼接字符串
		index : 循环索引
	 -->
	<foreach collection="ids" item="id" open=" where id in (" close=")" separator=",">
		#{id}
	</foreach>
</select>
public static void main(String[] args) {
	SqlSession session = MybatisUtil.getSession();
	
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	List<Student> students = studentMapper.selectList5(1,2,3,4);
	System.out.println(students);
	session.commit();
	session.close();
}

缓存

  在Mybatis中缓存分为2种,一级缓存和二级缓存,Mybatis默认是开启一级缓存.一级缓存指使用同一个SqlSession.

  二级缓存,需要主动设置开启,指SqlSessionFactory

一级缓存:SqlSession缓存 默认开启的

public static void main(String[] args) {
	// 第一次查询
	SqlSession session = MybatisUtil.getSession();
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	List<Student> students = studentMapper.selectList5(1,2,3,4);
	System.out.println(students);
	session.commit();
	session.close();
	//  第二次查询   使用不同 SqlSession
	SqlSesson session1 = MybatisUtil.getSession();
	studentMapper = session1.getMapper(StudentMapper.class);
	students = studentMapper.selectList5(1,2,3,4);
	System.out.println(students);
			
	// 第三次查询
	students = studentMapper.selectList5(1,2,3,4);
	System.out.println(students);
}
		
	// 以上查询一共执行查询语句2次,因为第二次和第三次使用的是同一个SqlSession,而执行sql语句是一样,则此时会执行缓存.

二级缓存:SqlSessionFactory

  在mybatis中,二级缓存需要手动开启,开启方式如下:

在核心配置文件中:

<settings>
	<!-- 开启二级缓存 -->
	<setting name="cacheEnabled" value="true"/>
</settings>

在mapper映射文件中:开启二级缓存

<!-- 此mapper文件中的查询都使用二级缓存 -->
<cache />

注意:

  mybatis会将查询的sql语句当做key,然后根据这个key从缓存中取,可能出现,数据更新了,但是缓存没有更新.第二个问题,如果sql语句不一样,只是发生了一定的变化,例如 大写换成小写等,此时则是2个key.浪费内存.

连接查询

  连接查询即多条联合查询.会出现查询的结果,一个pojo本身是无法全部包含.一般而言,表和表的关系,主要分为:

  一对多和多对一.以上两种关系,主要只是角度不同.

多对一:多个学生一个班级

方式一:定义类,将所有查询结果进行封装

package com.sxt.pojo;

public class Student {
	
	private Integer id; 	// 学生ID
	private String name; 	// 学生姓名	
	private Integer cId; 	// 学生班级	
	private String cName;	// 班级名称

	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getcId() {
		return cId;
	}
	public void setcId(Integer cId) {
		this.cId = cId;
	}
	public String getcName() {
		return cName;
	}
	public void setcName(String cName) {
		this.cName = cName;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", cId=" + cId + ", cName=" + cName + "]";
	}

}
<select id="selectAll1"  resultType="Student">
	select st.id as id,st.name as name,st.cid as cId,cl.name as cName from student2 st left join classes2 cl on st.cid = cl.id
</select>

对象封装:

public static void main(String[] args) {
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	List<Student> students = studentMapper.selectAll1();
	for (Student student : students) {
		Classes classes = new Classes();
		classes.setId(student.getcId());
		classes.setName(student.getcName());
		student.setClasses(classes);
	}
}

方式二:循环查询

public static void main(String[] args) {
		
	SqlSession session = MybatisUtil.getSession();
		
	StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	List<Student> students = studentMapper.selectAll2();
	for (Student student : students) {
		Integer cId = student.getcId();
		Classes classes = studentMapper.selectClasses(cId);
		student.setClasses(classes);
	}
		
	System.out.println(students);
	session.commit();
	session.close();
}
<select id="selectAll2"  resultType="Student">
	select st.id as id,st.name as name,st.cid as cId   from student2 st
</select>
	
<select id="selectClasses" resultType="Classes">
	select id ,name from classes2 where id = #{id}
</select>

方式三:使用ResultMap将属性封装成对象

<!-- 
    第一种方式:
        将属性进行封装
-->
<resultMap type="Student" id="BASE_RESULT_MAP">
	<id  column="id"  property="id"/>
	<result column="name" property="name"/>
	<result column="cId" property="cId"/>
	<!-- 
		association 多对一 
			property : 多对一中 多的类中的属性名
			javaType : 一所属的类
	 -->
	<association property="classes"  javaType="com.sxt.pojo.Classes"  >
		<result column="cId" property="id"/>
		<result column="cName" property="name"/>
	</association>
</resultMap>

<select id="selectAll1"  resultMap="BASE_RESULT_MAP">
	select st.id as id,st.name as name,st.cid as cId,cl.name as cName   
	from student2 st left join classes2 cl on st.cid = cl.id
</select>

方式四:循环查询

<resultMap type="Student" id="BASE_RESULT_MAP2">
	<id  column="id"  property="id"/>
	<result column="name" property="name"/>
	<result column="cId2" property="cId"/>
	<!-- 
	    association:表示多对一
		select : 获取一需执行的sql
		column : 将 column 的值当做参数传给  	select对应的查询语句
	-->
	<association property="classes1" javaType="com.sxt.pojo.Classes" select="selectClasses" column="cId2" />
</resultMap>

<select id="selectAll2"  resultMap="BASE_RESULT_MAP2">
	select st.id as id,st.name as name,st.cid as cId2   from student2 st
</select>
<select id="selectClasses" resultType="Classes">
	select id ,name from classes2 where id = #{id}
</select>

一对多:一个班级多个学生

方式一: 将数据进行解析封装

package com.sxt.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;

import com.sxt.mapper.ClassesMapper;
import com.sxt.mapper.StudentMapper;
import com.sxt.pojo.Classes;
import com.sxt.pojo.Student;
import com.sxt.util.MybatisUtil;

public class Test {
	public static void main(String[] args) {
		
	    SqlSession session = MybatisUtil.getSession();
		
	    StudentMapper studentMapper = session.getMapper(StudentMapper.class);
	    ClassesMapper classesMapper = session.getMapper(ClassesMapper.class);
		
	    List<Map<String, Object>> maps = classesMapper.selectAll1();
	    // List<Classes   ===>  List <Student>
	    // 创建Map  map装班级  map的key 是班级的id
	    // map 中的值是班级对象   每次读数据先从map中找班级  没有则创建新的班级放到map中去
	    Map<Integer,Classes> classMap = new HashMap<Integer,Classes>(); // 班级去重
	    for (Map<String, Object> map : maps) {
		    Integer id = (Integer) map.get("id");//班级ID
		    String name = (String)map.get("name");//班级名称
		    String stName = (String) map.get("stName"); //学生名称
		    Integer stId = (Integer) map.get("stId");//学生ID
		    Student st = new Student();
		    st.setId(stId);
		    st.setName(stName);
		    st.setcId(id);
		    Classes classes = new Classes();
		    // 判断map中是否存在该班级
		    if(classMap.containsKey(id)) {
			classes = classMap.get(id);
			classes.getStudents().add(st);
			continue;
		    }
		    classes.setId(id);
		    classes.setName(name);
		    List<Student> sts = new ArrayList<Student>();
		    sts.add(st);
		    // 班级设置学生
		    classes.setStudents(sts);
		    // 将班级放入到map容器中
		    classMap.put(id, classes);
	    }
	    System.out.println(classMap);
	    // 将Map中班级数据取出
	    Collection<Classes> values = classMap.values();
	    System.out.println(values);
        
	    session.commit();
	    session.close();
    }
}

方式二:mybatis属性封装

<resultMap type="Classes" id="BASE_RESULT_MAP1">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<!--
		collection : 一对多
		property : 一中多的属性名
		javaType : 属性类型
		ofType : collection中数据的类型
	 -->
	<collection property="students" javaType="list"  ofType="Student" >
		<result column="stId" property="id"/>
		<result column="stName" property="name"/>
		<result column="id" property="cId"/>
	</collection>
</resultMap>
		
<select id="selectAll2" resultMap="BASE_RESULT_MAP1">
	select cl.id as id,cl.name as name,st.id as stId,st.name as stName  from classes2 cl left join student2 st on  cl.id=st.cid
</select>

方式三:循环查询

<!-- 循环查询 -->
<!-- 查询所有班级 -->
<select id="selectAllClasses"  resultType="Classes">
	select id ,name from classes2 
</select>
<!-- 根据班级ID 查询学生 -->
<select id="selectStudentByClassId" resultType="Student">
	select id,name,cid as cId from student2 where cid = #{cId}
</select>
package com.sxt.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;

import com.sxt.mapper.ClassesMapper;
import com.sxt.pojo.Classes;
import com.sxt.pojo.Student;
import com.sxt.util.MybatisUtil;

public class Test {
	public static void main(String[] args) {
		SqlSession session = MybatisUtil.getSession();
		ClassesMapper classesMapper = session.getMapper(ClassesMapper.class);
		//查询出所有班级
		List<Classes> classess = classesMapper.selectAllClasses();
		for (Classes classes : classess) {
			Integer id = classes.getId();
			List<Student> sts = classesMapper.selectStudentByClassId(id);
			classes.setStudents(sts);
		}
		System.out.println(classess);
		session.commit();
		session.close();
	}
}

方式四:循环查

<resultMap type="Classes" id="BASE_RESULT_MAP2">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<!--
		collection : 一对多
			property : 一中多的属性名
			javaType : 属性类型
			ofType : collection中数据的类型
	-->
	<collection property="students" javaType="list"  ofType="Student" select="selectStudentByClassId" column="id" ></collection>	
</resultMap>

<!-- 循环查询 -->
<!-- 查询所有班级 -->
<select id="selectAllClasses"  resultMap="BASE_RESULT_MAP2">
	select id ,name from classes2 
</select>
<!-- 根据班级ID 查询学生 -->
<select id="selectStudentByClassId" resultType="Student">
	select id,name,cid as cId from student2 where cid = #{cId}
</select>

mybatis中的注解

package com.sxt.mapper;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.sxt.pojo.Student;

public interface StudentMapper {
	
	@Select("select id,name,cid as cId from student2")
	public List<Student> selectAll();
	
	@Select("select id,name,cid as cId from student2 where id = #{id}")
	public Student selectOne(@Param("id")Integer id);
	
	@Delete("delete from student2 where id = #{id}")
	public void delete(@Param("id")Integer id);
	
	@Update("update student2 set name=#{name},cid=#{cId}   where id=#{id}")
	public void update(Student st);
	//动态SQL
	@Select("<script>select id,name,cid as cId from student2  <where><if test='id !=null and id !=""'>and id=#{id}</if></where></script>")
	public List<Student> selectAll2(Map<String,Object> param);
	
}
原文地址:https://www.cnblogs.com/lyang-a/p/12563180.html