# Mybatis学习文档

1、简介

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了手动 JDBC 代码、手动设置参数、获取结果集。Sql语句放在 XML文件 或注解来配置和映射原生信息。

使用的人多!公司需要!但是应为用了反射,效率会下降,所有有些公司会使用原生的jdbc

1.1、优缺点

sql语句与代码分离,存放于xml配置文件中:

优点:便于维护管理,不用在java代码中找这些语句;
缺点: JDBC方式可以用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。

用逻辑标签控制动态SQL的拼接:
优点:用标签代替编写逻辑代码;
缺点:拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。不要使用变通的手段来应对这种复杂的语句。

查询的结果集与java对象自动映射:
优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。
缺点:对开发人员所写的SQL依赖很强。

编写原生SQL:
优点:接近JDBC,比较灵活。
缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如mysql数据库编程Oracle数据库,部分的sql语句需要调整。

1.2、Maven依赖

<dependencies>
  <!-- 单元测试 -->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.7</version>
    <scope>test</scope>
  </dependency>
  <!-- mybatis 核心 -->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
  </dependency>
  <!-- 数据库确定 -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
  </dependency>
</dependencies>

1.3、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>
  <!--数据源-->
  	<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://localhost:3306/ssm?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
 
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
        <!-- 下划线转驼峰式 -->
        <setting name="cacheEnabled" value="true"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logPrefix" value="sql."/>
    </settings>
  
    <!--设置别名-->
    <typeAliases>
        <package name="com.xinzhi.entity"/>
    </typeAliases>
  
    <!--注册Mapper-->
    <mappers>
        <mapper resource="mappers/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">
<mapper namespace="com.xinzhi.dao.UserMapper">
  	<select id="selectUser" resultType="com.xinzhi.entity.User">
  	select id,username,password from user
  	</select>
</mapper>

2、测试SQL

2.1、xml文件

useGeneratedKeys=“true” 开启返回主键ID

keyProperty=“id” 实体类字段

keyColumn=“id” 数据库字段

public interface UserMapper {
//根据id查询用户
User selectUserById(int id);
}  
<!--id方法名,parameterType参数类型,resultType返回值类型,#{}占位符,${}字符串拼串-->
<select id="selectUserById" resultType="com.xinzhi.entity.User" parameterType="int">
	select u_id , u_name , u_password from user where u_id = #{id}
</select>

2.2、注解

@Select("select u_id , u_name , u_password from user where u_id = #{id}")
public interface UserMapper {
//根据id查询用户
User selectUserById(int id);
} 

2.3、模糊查询

<select id=”getUsersByName”>
	select * from user where name like "%"#{name}"%"
</select>

<select id=”getUsersByName”>
	select * from user where name like concat('%', #{username}, '%')
</select>

2.4、@Param

传递单个参数时,不使用Param。多个参数时,需要使用Param确认属性,除了Param,还可以使用Map

public interface UserMapper {
//根据id修改用户名
User selectUserById(@Param("id") int id,@Param("name")String name){
  
};
} 

3、ResultMap

3.1、解决数据库列名和字段名不一致

<resultMap id="UserMap" type="User">
  <!-- id为主键 -->
  <id column="u_id" property="id"/>
  <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
  <result column="u_name" property="name"/>
  <result column="u_password" property="password"/>
</resultMap>

<select id="selectUserById" resultMap="UserMap">
	select u_id , u_name , u_password from user where u_id = #{id}
</select>

3.2、多表维护

1、多

在多的表维护比如查询员工的信息,要把他的部门信息从另一张表查出来,返回的是对象

//两张表,两个类
public class Dept {
    private int deptId;
    private String deptName;
} 

public class Employee {
    private int emId;
    private String emName;
    //维护关系,存放,查询部门信息
    private Dept dept;
}
<!--java类中维护关系的属性与表中的外键列名关联,查询完后拿到数据,再跟一条sql查询父表的数据-->
<resultMap id="EmployeeDept" type="com.xinzhi.entity.Employee">
  <!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
  <association property="dept" column="dept_id" javaType="com.xinzhi.entity.Dept" select="getDept"/>
</resultMap>

<select id="findAll" resultMap="EmployeeDept">
		select * from employee
</select>

<select id="getDept" resultType="com.xinzhi.entity.Dept" parameterType="int">
		select * from dept where dept_id = #{id}
</select>
2、一

查询部门信息时,把所属部门的员工信息也查出来 ,返回的是一个集合

JavaType和ofType都是用来指定对象类型的,但是JavaType是用来指定pojo中属性的类型,而ofType指定的是
映射到list集合属性中pojo的类型

public class Dept {
    private int deptId;
    private String deptName;
    //维护关系的字段,存员,查询工信息
    private List<Employee> employees;
}  
<resultMap id="DeptEmployee" type="com.xinzhi.entity.Dept">
  <id column="dept_id" property="deptId"/>
  <!--column是一对多的外键 , 写的是一的主键的列名-->
  <collection property="employees" javaType="ArrayList"ofType="com.xinzhi.entity.Employee" column="dept_id"
  select="getEmployee"/>
</resultMap>

<select id="findDeptById" resultMap="DeptEmployee">
	select * from dept where dept_id = #{id}
</select>

<select id="getEmployee" resultType="com.xinzhi.entity.Employee">
	select em_id,em_name from employee where dept_id = #{id}
</select>

3、懒加载

只有在连表查询的时候才有用。只有在使用维护数据时才会发sql去查询,提高了效率。默认是不开启的

<settings>
    <!--懒加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

4、动态sql

元素作用备注
if判断语句单条件分支判断
choose、when、otherwise相当于Java中的 case when语句多条件分支判断
trim、where、set辅助元素用于处理一些SQL拼装问题
foreach循环语句在in语句等列举条件常用

添加

prefix代表的是语句的前缀,而prefixOverrides代表的是你需要去掉的那种字符串,
suffix表示语句的后缀,suffixOverrides代表去掉的后缀字符串

<insert id="insertUser" parameterType="user">
    insert into user
    (
    <trim suffixOverrides=",">
        <if test="username != null and username != ''">
            username,
        </if>
        <if test="password != null and password != ''">
            password,
        </if>
    </trim>
    )
    values
    (
    <trim suffixOverrides=",">
        <if test="username != null and username != ''">
            #{username},
        </if>
        <if test="password != null and password != ''">
            #{password},
        </if>
    </trim>
    )
</insert>

多条件查询

<select id="selectUsersWhere" parameterType="user" resultType="user">
    select id,username,password from user
    <where>
      	<!--只有在非空且非空串的时候才有值,查询时可以传空,全空就查到所有-->
        <if test="id != null and id != ''">
            id = #{id}
        </if>
        <if test="username != null and username != ''">
            And username LIKE concat('%', #{username}, '%')
        </if>
        <if test="password != null and password != ''">
            And password = #{password}
        </if>
    </where>
</select>

根据一堆id查询

<select id="selectUserByIds" resultType="user" parameterType="int">
    SELECT * FROM user 
  	WHERE id IN
  	<!--ids传进来的数组,open开始给一个(,close关闭给一个),separator用,隔开,将ids遍历成一个个id-->
    <foreach collection="ids" open="(" close=")" separator="," item="id">
            #{id}
    </foreach>
</select>

修改

在update语句中,如果我们只想更新某几个字段的值,这个时候可以使用set元素配合if元素来完成。注意:set元素遇到,会自动去掉

<update id="updateUser" parameterType="user">
    UPDATE user
    <set>
        <if test="username != null and username != ''">
            username = #{username},
        </if>
        <if test="password != null and password != ''">
            password = #{password}
        </if>
    </set>
    WHERE id = #{id}
</update>

根据一堆id删除

<delete id="deleteUserByIds" parameterType="int">
    delete FROM user
    WHERE id IN
    <foreach collection="ids" open="(" close=")" separator="," item="id">
        #{id}
    </foreach>
</delete>

5、日志

可以查看发出的sql,更方便的调试

5.1、标准日志

<settings> 
		<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>  

5.2、log4j

maven依赖

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>  

编写 配置文件log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG  

mybatis.xml

<settings>
	<setting name="logImpl" value="LOG4J"/>
</settings>  

6、缓存

  • 如果缓存中有数据,就不用从数据库获取,大大提高系统性能
  • mybatis提供一级缓存和二级缓存

一级缓存

  • 一级缓存在mybatis中默认开启,是sqlsession级别的缓存。
  • 在操作数据库时,需要构造sqlsession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据
  • 不同的sqlsession之间的缓存区域是互相不影响的
  • 在同一sqlsession中发送同一sql,不会重复发送而是直接从缓存中拿
  • 如果sqlsession执行了commit操作(插入,更新,删除),会清空sqlsession中的一级缓存,避免脏读

缓存失效

  • sqlSession不同
  • 当sqlSession对象相同的时候,查询的条件不同
  • 当sqlSession对象相同,两次查询之间进行了插入的操作
  • 当sqlSession对象相同,手动清除了一级缓存中的数据

二级缓存

  • 二级缓存是mapper级别的,不同sqlsession共用二级缓存

  • 需要commit

  • 二级缓存需要开启

    <settings>
      <!--开启二级缓存-->
      <setting name="cacheEnabled" value="true"/>
    </settings>
    
    <!--需要开启本Mapper的namespace下的二级缓存-->
    <!--LRU(Least Recently Used),最近最少使用的,最长时间不用的对象-->
    <!--100秒刷新,如果你不配置它,那么当SQL被执行的时候才会去刷新缓存-->
    <cache eviction="LRU" flushInterval="10000"/>
    

单个sql可以禁用二级缓存

<select id="getStudentById" parameterType="java.lang.Integer" resultType="Student"
useCache="false"> 

刷新缓存

<select id="getStudentById" parameterType="java.lang.Integer" resultType="Student"
flushCache="true">

第三方缓存

存入第三方,比如ehcache,Memcached、redis 等

测试ehcache,引依赖
<dependency>
  <groupId>org.mybatis.caches</groupId>
  <artifactId>mybatis-ehcache</artifactId>
  <version>1.1.0</version>
</dependency>  
配置mapper
<mapper namespace = “com.xinzhi.entity.User” >
<cache type="org.mybatis.caches.ehcache.EhcacheCache" eviction="LRU"
flushInterval="10000" size="1024" readOnly="true"/>
</mapper>
ehcache的 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
    <!--
    diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
    user.home – 用户主目录
    user.dir – 用户当前工作目录
    java.io.tmpdir – 默认临时文件路径
    -->
	<diskStore path="./tmpdir/Tmp_EhCache"/>
	<defaultCache
    eternal="false"
    maxElementsInMemory="10000"
    overflowToDisk="false"
    diskPersistent="false"
    timeToIdleSeconds="1800"
    timeToLiveSeconds="259200"
    memoryStoreEvictionPolicy="LRU"/>
</ehcache>

数据一致性

怎么能保证缓存中的数据就是正确的,在MyBatis中,当mapper中有更新操作时,直接清空缓存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值