Mybatis详解

在这里插入图片描述

Mybatis与Hibernate区别

  • hibernate:它是一个标准的全自动的orm框架,可以自动生成sql语句,比较重量级,学习成本高.对象/关系映射能力强,数据库无关性好
    1:优点:高度封装,使用起来不用写sql,开发的时候,会减低开发周期.
    2:缺点:sql语句无法优化,学习门槛高,要精通门槛更高。性能和对象模型之间如何权衡
    3: 应用场景
    oa(办公自动化系统), erp(企业的流程系统)等,还有一些政府项目,总的来说,在用于量不大,并发量小的时候使用.
  • mybatis:它不完全是一个orm框架, 它是对jdbc的轻量级封装, 学习成本低,比较简单,需要程序员自己编写Sql语句
    1:优点:学习成本低, sql语句可以优化, 执行效率高,速度快
    2:缺点:编码量较大,会拖慢开发周期
    3:应用场景: 互联网项目,比如电商,P2p等。总的来说是用户量较大,并发高的项目.

MyBatis的一级缓存和二级缓存

  • Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象
  • Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。二级缓存是可以跨SqlSession的。

介绍

  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatement、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

    解释
  • SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
  • mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
  • 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
  • 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
  • mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
  • Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
  • Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
  • Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

环境搭建

  • SqlMapConfig.xml是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">
<configuration>
	<!-- 和spring整合后 environments配置将废除-->
	<environments default="development">
		<environment id="development">
		<!-- 使用jdbc事务管理-->
			<transactionManager type="JDBC" />
		<!-- 数据库连接池-->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="123" />
			</dataSource>
		</environment>
	</environments>
	
</configuration>
  • 日志配置
#Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
  • 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">

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1MldSmpg-1569727837428)(https://img-blog.csdn.net/20170716094020249?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWVpd2VpbGFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]

  • mybatis框架需要加载映射文件,将Users.xml添加在SqlMapConfig.xml,如下:
<mappers>
		<mapper resource="User.xml"/>
</mappers>

细节

  • #{}占位符:占位
    如果传入的是基本类型,那么#{}中的变量名称可以随意写
    如果传入的参数是pojo类型,那么#{}中的变量名称必须是pojo中的属性
  • ${}拼接符:字符串原样拼接
    如果传入的是基本类型,那么${}中的变量名必须是value
    如果传入的参数是pojo类型,那么${}中的变量名称必须是pojo中的属性
    注意:使用拼接符有可能造成sql注入,在页面输入的时候可以加入校验,不可输入sql关键字,不可输入空格

Dao的开发方式

Mapper动态代理方式

Mapper接口开发方法只需要程序员编写Dao接口,由Mybatis框架根据接口定义创建接口的动态代理对象。

  • Mapper接口开发需要遵循以下规范:
    Mapper.xml(映射文件)文件中的namespace等于Dao接口的全路径名称
    Mapper.xml中sql语句id要等于Mapper接口方法名称
    mapper.xml中传入的parameterType的类型等于Mapper接口方法的输入参数类型
    mapper.xml中定义的每个sql的resultType的类型等于Mapper接口方法的返回值类型。
  • 定义mapper映射文件UserMapper.xml(内容同Users.xml),需要修改namespace的值为 UserMapper接口路径。将UserMapper.xml放在classpath 下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">
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<!-- 自定义条件查询用户列表 -->
	<select id="findUserByUsername" parameterType="java.lang.String" 
			resultType="cn.itcast.mybatis.po.User">
	   select * from user where username like '%${value}%' 
	</select>
<!-- 添加用户 -->
	<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
	<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
		select LAST_INSERT_ID() 
	</selectKey>
	  insert into user(username,birthday,sex,address) 
	  values(#{username},#{birthday},#{sex},#{address})
	</insert>

</mapper>
  • 测试
Public class UserMapperTest extends TestCase {

	private SqlSessionFactory sqlSessionFactory;
	
	protected void setUp() throws Exception {
		//mybatis配置文件
		String resource = "sqlMapConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		//使用SqlSessionFactoryBuilder创建sessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

	
	@Test
	public void testFindUserByUsername() throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		List<User> list = userMapper.findUserByUsername("张");
		System.out.println(list.size());

	}
Public void testInsertUser() throws Exception {
		//获取session
		SqlSession session = sqlSessionFactory.openSession();
		//获取mapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);
		//要添加的数据
		User user = new User();
		user.setUsername("张三");
		user.setBirthday(new Date());
		user.setSex("1");
		user.setAddress("北京市");
		//通过mapper接口添加用户
		userMapper.insertUser(user);
		//提交
		session.commit();
		//关闭session
		session.close();
	}
	

}

SqlMapConfig.xml配置文件

  • properties(属性)
  • settings(全局配置参数)
  • typeAliases(类型别名)
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境集合属性对象)
  • environment(环境子属性对象)
  • transactionManager(事务管理)
  • dataSource(数据源)
  • mappers(映射器)

properties

  • SqlMapConfig.xml可以引用java属性文件中的配置信息如下:

在classpath下定义db.properties文件,

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

SqlMapConfig.xml引用如下:

<properties resource="db.properties"/>
	<environments default="development">
		<environment id="development">
			<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>

注意: MyBatis 将按照下面的顺序来加载属性:

  • 在 properties 元素体内定义的属性首先被读取。
  • 然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。

typeAliases

  • mybatis支持别名:
别名	映射的类型
_byte 	byte 
_long 	long 
_short 	short 
_int 	int 
_integer 	int 
_double 	double 
_float 	float 
_boolean 	boolean 
string 	String 
byte 	Byte 
long 	Long 
short 	Short 
int 	Integer 
integer 	Integer 
double 	Double 
float 	Float 
boolean 	Boolean 
date 	Date 
decimal 	BigDecimal 
bigdecimal 	BigDecimal 
map   	Map
  • 自定义别名:
    在SqlMapConfig.xml中配置:
<typeAliases>
	<!-- 单个别名定义 -->
	<typeAlias alias="user" type="cn.itcast.mybatis.po.User"/>
	<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
	<package name="cn.itcast.mybatis.po"/>
	<package name="其它包"/>
</typeAliases>

mappers(映射器)

  • Mapper配置的几种方法:
<mapper resource=" " />
使用相对于类路径的资源
如:<mapper resource="sqlmap/User.xml" />
<mapper class=" " />
使用mapper接口类路径
如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

package name=""/>
注册指定包下的所有mapper接口
如:<package name="cn.itcast.mybatis.mapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

输入映射和输出映射

输入参数映射

  • Sql语句
SELECT * FROM user where username like '%刘%'
  • Mapper文件
<select id="findUserByQueryVo" parameterType="queryvo" resultType="user">
	SELECT * FROM user where username like '%${user.username}%'
</select>
  • 测试方法
@Test
	public void testFindUserByQueryVo() throws Exception {
		SqlSession sqlSession = sessionFactory.openSession();
		//获得mapper的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		//创建QueryVo对象
		QueryVo queryVo = new QueryVo();
		//创建user对象
		User user = new User();
		user.setUsername("刘");
		queryVo.setUser(user);
		//根据queryvo查询用户
		List<User> list = userMapper.findUserByQueryVo(queryVo);
		System.out.println(list);
		sqlSession.close();
	}
>

动态sql

通过mybatis提供的各种标签方法实现动态拼接sql。

  • If
<!-- 传递pojo综合查询用户信息 -->
	<select id="findUserList" parameterType="user" resultType="user">
	select * from user where 1=1 
		<if test="id!=null">
		and id=#{id}
		</if>
		<if test="username!=null and username!=''">
		and username like '%${username}%'
		</if>
	</select>

注意要做不等于空字符串校验。

  • Where
    <where />可以自动处理第一个and。
<select id="findUserList" parameterType="user" resultType="user">
		select * from user 
		<where>
		<if test="id!=null and id!=''">
		and id=#{id}
		</if>
		<if test="username!=null and username!=''">
		and username like '%${username}%'
		</if>
		</where>
	</select>
  • Foreach
    传入多个id查询用户信息,用下边两个sql实现:
SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)

在povo中定义list属性ids存储多个用户id,并添加getter/setter方法

  • mapper.xml

<if test="ids!=null and ids.size>0">
	<foreach collection="ids" open=" and id in(" close=")" item="id" separator="," >
	    		#{id}
	    	</foreach>
</if>
  • Sql片段
    可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的,如下:
<!-- 传递pojo综合查询用户信息 -->
	<select id="findUserList" parameterType="user" resultType="user">
		select * from user 
		<where>
		<if test="id!=null and id!=''">
		and id=#{id}
		</if>
		<if test="username!=null and username!=''">
		and username like '%${username}%'
		</if>
		</where>
	</select>
  • 将where条件抽取出来:
<sql id="query_user_where">
	<if test="id!=null and id!=''">
		and id=#{id}
	</if>
	<if test="username!=null and username!=''">
		and username like '%${username}%'
	</if>
</sql>
  • 使用include引用:
<select id="findUserList" parameterType="user" resultType="user">
		select * from user 
		<where>
		<include refid="query_user_where"/>
		</where>
	</select>

注意:如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如下:

<include refid="namespace.sql片段”/>

关联查询

一对一关联




  • 局部来看,一个订单只能属于一个用户(根据订单查询订单和用户信息)

一对多关联

用户和订单情况,一个用户有多个订单,在user实体类中定义List<User>生成set/get方法

  • mapper.xml

Mybatis整合spring

传统DAO实现

  • 传统dao的开发方式
    接口+实现类来完成。需要dao实现类需要继承SqlsessionDaoSupport类
  • dao实现类
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {

	@Override
	public User findUserById(int id) throws Exception {
		SqlSession session = getSqlSession();
		User user = session.selectOne("test.findUserById", id);
		//不能关闭SqlSession,让spring容器来完成
		//session.close();
		return user;
	}

	@Override
	public void insertUser(User user) throws Exception {
		SqlSession session = getSqlSession();
		session.insert("test.insertUser", user);
		session.commit();
		//session.close();
	}

}
  • 配置dao
    把dao实现类配置到spring容器中
<!-- 配置UserDao实现类 -->
	<bean id="userDao" class="cn.itcast.dao.UserDaoImpl">
		<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
	</bean>
  • 初始化:
private ApplicationContext applicationContext;
@Before
public void setUp() throws Exception{
	String configLocation = "classpath:spring/ApplicationContext.xml";
	//初始化spring运行环境
	applicationContext = new ClassPathXmlApplicationContext(configLocation);
}

测试:

@Test
public void testFindUserById() throws Exception {
	UserDao userDao = (UserDao) applicationContext.getBean("userDao");
	User user = userDao.findUserById(1);
	System.out.println(user);
}

动态代理实现

  • 开发mapper文配置mapper代理
<!-- 配置mapper代理对象 -->
	<bean class="org.mybatis.spring.mapper.MapperFactoryBean">
		<property name="mapperInterface" value="cn.itcast.mybatis.mapper.UserMapper"/>
		<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
	</bean>
  • 扫描包形式配置mapper
<!-- 使用扫描包的形式来创建mapper代理对象 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="cn.itcast.mybatis.mapper"></property>
	</bean>
注意: 每个mapper代理对象的id就是类名,首字母小写

这里写图片描述

mybatis plus

mybatis plus是一款专门针对于传统MyBatis开发中sql需要手动进行映射配置繁琐缺点的一款框架技术,这款框架技术提供了十分丰富的api供开发者们使用,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sise</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatisplus-spring-boot-starter</artifactId>
            <version>1.0.5</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>2.3</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>


</project>
  • 通常我们在开发的时候都会自定义一个Dao层,mybatis plus里面提供了一个叫做BaseMapper的接口,内部已经提供了相当多的crud操作函数的封装。可以来仔细查看一下该接口的内容:
/**
 * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
 */
public interface BaseMapper<T> {

    /**
     * 插入一条记录
     */
    Integer insert(T entity);

    /**
     * 插入一条记录
     */
    Integer insertAllColumn(T entity);

    /**
     * 根据 ID 删除
     */
    Integer deleteById(Serializable id);

    /**
     * 根据 columnMap 条件,删除记录
     * @param columnMap 表字段 map 对象
     */
    Integer deleteByMap(@Param("cm") Map<String, Object> columnMap);

    /**
     * 根据 entity 条件,删除记录
     * @param wrapper 实体对象封装操作类(可以为 null)
     */
    Integer delete(@Param("ew") Wrapper<T> wrapper);

    /**

     * 删除(根据ID 批量删除)
     * @param idList 主键ID列表
     */
    Integer deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    /**
     * 根据 ID 修改
     * @param entity 实体对象
     * @return int
     */
    Integer updateById(@Param("et") T entity);

    /**
     * 根据 ID 修改
     * @param entity 实体对象
     */
    Integer updateAllColumnById(@Param("et") T entity);

    /**
     * 根据 whereEntity 条件,更新记录
     * @param entity  实体对象
     * @param wrapper 实体对象封装操作类(可以为 null)
     */
    Integer update(@Param("et") T entity, @Param("ew") Wrapper<T> wrapper);

    /**
     * 根据 whereEntity 条件,更新记录
     * @param setStr  set字符串
     * @param wrapper 实体对象封装操作类(可以为 null)
     */
    Integer updateForSet(@Param("setStr") String setStr, @Param("ew") Wrapper<T> wrapper);

    /**
     * 根据 ID 查询
     * @param id 主键ID
     */
    T selectById(Serializable id);

    /**
     * 查询(根据ID 批量查询)
     * @param idList 主键ID列表
     * @return List<T>
     */
    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    /**
     * 查询(根据 columnMap 条件)
     * @param columnMap 表字段 map 对象
     * @return List<T>
     */
    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

    /**
     * 根据 entity 条件,查询一条记录
     * @param entity 实体对象
     */
    T selectOne(@Param("ew") T entity);

    /**
     * 根据 Wrapper 条件,查询总记录数
     * @param wrapper 实体对象
     * @return int
     */
    Integer selectCount(@Param("ew") Wrapper<T> wrapper);

    /**
     * 根据 entity 条件,查询全部记录
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return List<T>
     */
    List<T> selectList(@Param("ew") Wrapper<T> wrapper);

    /**

     * 根据 Wrapper 条件,查询全部记录
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return List<T>
     */
    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> wrapper);

    /**
     * 根据 Wrapper 条件,查询全部记录
     * 注意: 只返回第一个字段的值
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return List<Object>
     */
    List<Object> selectObjs(@Param("ew") Wrapper<T> wrapper);

    /**
     * 根据 entity 条件,查询全部记录(并翻页)
     * @param rowBounds 分页查询条件(可以为 RowBounds.DEFAULT)
     * @param wrapper   实体对象封装操作类(可以为 null)
     * @return List<T>
     */
    List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);

    /**
     * 根据 Wrapper 条件,查询全部记录(并翻页)
     * @param rowBounds 分页查询条件(可以为 RowBounds.DEFAULT)
     * @param wrapper   实体对象封装操作类
     * @return List<Map<String, Object>>
     */
    List<Map<String, Object>> selectMapsPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);

}
  • 分页查询
   @GetMapping(value = "/selectAllInPage")
    public List<Teacher> selectAllInPage(int pageNumber,int pageSize){
        Page<Teacher> page =new Page<>(pageNumber,pageSize);
        EntityWrapper<Teacher> entityWrapper = new EntityWrapper<>();
        entityWrapper.ge("id", 1);
        return teacherMapper.selectPage(page,entityWrapper);
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值