【JAVA】Mybatis

Mybatis 概述

原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了 Google Code,随着开发团队转投Google Code 旗下, iBatis3.x正式更名为MyBatis。

MyBatis 是一款优秀的持久层框架。

MyBatis 避免了几乎所有的 JDBC 代码手动设置参数以及手动获取结果集的操作。

MyBatis 可以使用 XML 或注解来配置和映射,将数据库中的记录映射成Java 的 POJO(Plain Old Java Objects,普通的 Java 对象),是一种 ORM(ORMObject Relational Mapping 对象关系映射)实现.

它支持动态 SQL 以及数据缓存.

Mybatis 将基本的 JDBC 常用接口封装,对外提供操作即可.

Mybatis 中文官网 https://mybatis.org/mybatis-3/zh/getting-started.html

Mybatis 源码下载

https://github.com/mybatis/mybatis-3/releases

MyBatis 环境搭建

1.创建一张表和表对应的实体类

2.导入 MyBatis jar 包,mysql 数据库驱动包

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>3.4.2</version>

</dependency>

3.创建 MyBatis 全局配置文件

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config

3.0//EN" "" target="_blank">http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<environments default="development">

<environment id="development">

<dataSource type="POOLED">

<property name="driver" value="" />

<property name="url" value="" />

<property name="username" value="" />

<property name="password" value=""/>

</dataSource>

</environment>

</environments>

</configuration>

4.创建 sql 映射文件

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"" target="_blank">http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="接口地址">

定义 sql 语句

</mapper>

5. 定义接口

在接口中定义方法

public interface UserDao{

}

6.测试 MyBatis

读取配置文件

Reader reader = Resources.getResourceAsReader("mybatis-config.xml");

创建 SqlSessionFactory

SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);

创建 SqlSession

SqlSession sqlSession = sessionFactory.openSession();

获得接口代理对象

sqlSession.getMapper(接口.class);

sqlSession .close();关闭;

API 接口说明

SqlSessionFactory 接口

使用 SqlSessionFactory 来创建 SqlSession,一旦创建 SqlSessionFactory 就会在整个应用过程中始终存在。由于创建开销较大,所以没有理由去销毁再创建它,一个应用运行中也不建议多次创建SqlSessionFactory。

SqlSession 接口

Sqlsession 意味着创建与数据库链接会话,该接口中封装了对数据库操作的方法,与数据库会话完成后关闭会话。

Mybatis-Dao 层 Mapper 接口化开发

Mapper 接口开发方式只需要程序员编写 Mapper 接口,由 Mybatis 框架创建接口的动态代理对象使用 sqlsession.getMapper(接口.class);获得代理对象.

Mapper 接口开发需要遵循以下规范:

1、 Mapper.xml 文件中的 namespace 与 mapper 接口的类路径相同.

2、 Mapper 接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同.

3、 Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的

parameterType 的类型相同.

4、 Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的

resultType 的类型相同.

Mybatis 日志

具体选择哪个日志实现由 MyBatis 的内置日志工厂确定。它会使用最先找到的。

Mybatis 内置的日志工厂提供日志功能,具体的日志实现有以下几种方式:SLF4J|LOG4J|JDK_LOGGINGCOMMONS_LOGGING|STDOUT_LOGGING

配置日志

<settings>

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

</settings>

参数传递

单个参数直接传递

User selectUsers(int id);

多个参数使用@Param(“id”)绑定

User selectUsers(@Param(“id”)int id,@Param(“name”)String name);

    <select id="selectUsers" resultType="User">
        select id, username, password from users where id = #{id} and username=#{name}
    </select>

如果传入一个复杂的对象,就需要使用 parameterType 参数进行类型定义,例如:

void insertUser(User user);

<insert id="insertUser" parameterType="User">
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>

增删改查

<insert id="唯一标识" useGeneratedKeys="把新增加的主键赋值到自己定义的
keyProperty " keyProperty=“ 接收主键的属性 parameterType="参数类型">
    insert into
        user(userName,userAge)values(#{userName},#{userAge})
    </insert>
</mapper>

#{} 和${}区别

#{} 占位符,是经过预编译的,编译好 SQL 语句再取值,#方式能够防止 sql 注入

#{}:select * from t_user where uid=#{uid}

${} 拼接符,会传入参数字符串,取值以后再去编译 SQL 语句,$方式无法防止 Sql注入 ${}

${}:select * from t_user where uid= '1'

注意:MyBatis 排序时使用 order by 动态参数时需要注意,用$而不是#

修改

<update id="唯一标识" parameterType=“参数类型">
update 
    ts_user set userName = #{userName},userAge = #{userAge}
    where 
    userId = #{userId}
</update>

删除

<delete id="唯一标识" parameterType="参数类型">
    delete from ts_user where userId = #{id}
</delete>

查询

<select id="唯一标识" resultType="返回结果集类型">
    select * 
    from ts_user where id= #{id}
</select>

结果处理

简单类型输出映射

返回简单基本类型
<select id="findUserInfoCount" resultType="int">
    select count(*) from userInfo
</select>

对象映射

如果表中的类名与类中的属性名完全相同,mybatis会自动将查询结果封装到POJO对象中.

如果java中使用标准驼峰命名,数据库中使用下划线连接命名,可以开始全局设置实现自动转换。

<setting name="mapUnderscoreToCamelCase" value="true"/>
<select id="findUserInfoById" parameterType="int"resultType="User">
    select * from t_user where id=#{id}
</select>

特殊处理定义 resultMap

定义 resutlMap

<resultMap id="userResultMap" type="User">
    <id column="id" property="id_"/>
    <result property="userName" column="user_Name_" />
    <result property="userAge" column="user_age" />
</resultMap>

(1). resutlMap 的 id 属性是 resutlMap 的唯一标识,本例中定义为“useresultMap”

(2). resutlMap 的 id 属性是映射的 POJO 类

(3). id 标签映射主键,result 标签映射非主键

(4). property 设置 POJO 的属性名称,column 映射查询结果的列名称

使用 resutlMap

使用 resultMap

<select id="findUserInfoResultMap" resultMap="userResultMap">
    SELECT id id_,user_name,user_age FROM t_user
</select>

(1). 本例的输出映射使用的是 resultMap,而非 resultType

(2). resultMap 引用了 userResultMap

多表关联处理结果集

resultMap 元素中 association , collection 元素.

Collection 关联元素处理一对多关联。

• 部门与员工一对多关系

• 部门一方,配置多方集合

• 员工多方,在多方配置一方

• 使用 resultMap 组装查询结果

• 使用 resultMap 组装查询结果

嵌套查询

将一个多表关联查询拆分为多次查询,先查询主表数据,然后查询关联表数据.

<association property="dept" javaType="Dept"

select="findDeptByID" column="dept_id"></association>

(1). select:指定关联查询对象的 Mapper Statement ID 为 findDeptByID。

(2). column="dept_id":关联查询时将 dept_id 列的值传入 findDeptByID,并将 findDeptByID 查询的结果映射到 Emp 的 dept 属性中。

(3).collection 和 association 都需要配置 select 和 column 属性,两者配置方法相同。

注解方式

常用注解标签

@Insert : 插入 sql , 和 xml insert sql 语法完全一样

@Select : 查询 sql, 和 xml select sql 语法完全一样

@Update : 更新 sql, 和 xml update sql 语法完全一样

@Delete : 删除 sql, 和 xml delete sql 语法完全一样

@Param : 入参

@Results : 设置结果集合

@Result : 结果

使用案例

查询所有信息

@Select("select * from t_emp")

@Results(id = "empMap",value = {

@Result(column = "emp_id",property = "empId",id = true),

@Result(column = "emp_name",property = "empName"),

@Result(column = "emp_tel",property = "empTel"),

@Result(column = "emp_education",property = "empEducation"),

@Result(column = "emp_birthday",property = "empBirthday")

})

List<Employee> getAll();

查询单个信息

@Select("select * from t_emp where emp_id=#{empId}")

@ResultMap(value="empMap")

Employee getById(@Param("empId") Integer empId);

插入信息

@Insert("insert into t_emp (emp_id, emp_name, emp_tel, " +

" emp_education, emp_birthday, fk_dept_id" +

" )" values (#{empId}, #{empName}, #{empTel}, " +

" #{empEducation}, #{empBirthday}, #{fkDeptId}" +

" )")

int insert(Employee record);

删除信息

@Delete("delete from t_emp where emp_id=#{empId}")

int deleteByPrimaryKey(@Param("empId") Integer empId);

Mybatis 动态 SQL

MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空格或在列表的最后省略逗号。动态 SQL 可以彻底处理这种痛苦。

MyBatis 中用于实现动态 SQL 的元素主要有:

If

where

trim

set

choose (when, otherwise)

foreach

If 元素

if 标签可以对传入的条件进行判断

思考:如果上面的这条 sql 语句中没有默认的 type=1 会是什么样子的。

查询条件

对于查询条件个数不确定的情况,可使用<where>元素。如下:

<select id="id" parameterType="“ resultType="">
SELECT xxx... FROM table t
    <where>
        <if test="name != null &amp; name!=’’ ">
            name like #{name}
        </if>
        <if test="age!=null &amp; age>0">
            AND age> #{value}
        </if>
    </where>
</select>

<where>元素会进行判断,如果它包含的标签中有返回值的话,它就插入一个‘where’。

此外,如果标签返回的内容是以 AND 或 OR 开头,它会剔除掉 AND 或 OR。

trim 元素

where 标签,其实用 trim 也可以表示,当 WHERE 后紧随 AND 或则 OR 的时候,就去除 AND 或者OR。prefix 前缀,prefixOverrides 覆盖首部指定内容。

Choose 元素

Set 元素可以把最后一个逗号去掉

也可以使用 trim 实现

foreach 元素

主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。foreach元素的属性主要有 item,index,collection,open,separator,close。

item 表示集合中每一个元素进行迭代时的别名,index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open 表示该语句以什么开始,separator 表示在每次进行迭代之间以什么符号作为分隔符,close 表示以什么结束,在使用 foreach 的时候最关键的也是最容易出错的就是 collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的。

– 如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list ;

– 如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为array;

特殊符号处理

在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<>等,正常书写 mybatis 会报错,需要对这些符号进行转义。具体转义如下所示:

特殊字符 转义字符

< &lt

> &gt

" &quot

’ &apos

& &amp

除了可以使用上述转义字符外,还可以使用<![CDATA[]]>来包裹特殊字符。如下所示:

<if test="id != null">

AND <![CDATA[ id <> #{id} ]]>

</if>

<![CDATA[ ]]>是 XML 语法。在 CDATA 内部的所有内容都会被解析器忽略。

但是有个问题那就是 <if> </if> <where> </where><choose> </choose> <trim> </trim> 等这些标签都不会被解析,所以我们只把有特殊字符的语句放在 <![CDATA[ ]]> 尽量缩小<![CDATA[ ]]>的范围。

mybatis 一级缓存二级缓存

为什么使用缓存

缓存(cache)的作用是为了减去数据库的压力,提高查询性能。缓存实现的原理是从数据库中查询出来的对象在使用完后不要销毁,而是存储在内存(缓存)中,当再次需要获取该对象时,直接从内存(缓存)中直接获取,不再向数据库执行select 语句,从而减少了对数据库的查询次数,因此提高了数据库的性能。

Mybatis 有一级缓存和二级缓存。一级缓存的作用域是同一个 SqlSession,在同一个 sqlSession 中两次执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个 sqlSession 结束后该 sqlSession 中的一级缓存也就不存在了。Mybatis 默认开启一级缓存。

二级缓存是多个 SqlSession 共享的,其作用域是同一个 namespace,不同的sqlSession 两次执行相同 namespace 下的 sql 语句且向 sql 中传递参数也相同即最终执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。

Mybatis 默认没有开启二级缓存需要在 setting 全局参数中配置开启二级缓存。

一级缓存

Mybatis 对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个 SqlSession 而言。所以在参数和 SQL 完全一样的情况下,我们使用同一个 SqlSession 对象调用一个 Mapper 方法,往往只执行一次 SQL,因为使用 SelSession 第一次查询后,MyBatis 会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession 都会取出当前缓存的数据,而不会再次发送 SQL 到数据库。

一级缓存的生命周期

a、MyBatis 在开启一个数据库会话时,会 创建一个新的 SqlSession 对象,SqlSession 对象中会有一个新的 Executor 对象。Executor 对象中持有一个新的 PerpetualCache 对象,如果 SqlSession 调用了 close()方法,会释放掉一级缓存 PerpetualCache 对象,一级缓存将不可用。

b、如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象中的数据,但是该对象仍可使用。

c、SqlSession 中执行了任何一个 update 操作(update()、delete()、insert()) ,都会清空缓存的数据,但是该对象可以继续使用。

二级缓存

二级缓存是 SqlSessionFactory 级别的,根据 mapper 的 namespace 划分区域

的,相同 namespace 的 mapper 查询的数据缓存在同一个区域,如果使用

mapper 代理方法每个 mapper 的 namespace 都不同,此时可以理解为二级缓

存区域是根据 mapper 划分。

每次查询会先从缓存区域查找,如果找不到则从数据库查询,并将查询到数据写

入缓存。Mybatis 内部存储缓存使用一个 HashMap,key 为

hashCode+sqlId+Sql 语句。value 为从查询出来映射生成的 java 对象。

sqlSession 执行 insert、update、delete 等操作 commit 提交后会清空缓存区

域,防止脏读。二级缓存参考下图所示:

MyBatis 的缓存机制整体设计以及二级缓存的工作模式

配置二级缓存配置

第一步:启用二级缓存

在 SqlMapperConfig.xml 中启用二级缓存,如下代码所示,当cacheEnabled 设置为 true 时启用二级缓存,设置为 false 时禁用二级缓存。

<setting name="cacheEnabled" value="true"/>

第二步:对象序列化

将所有的 POJO 类实现序列化接口 Java.io. Serializable。

第三步:配置映射文件

在 Mapper 映射文件中添加<cache />,表示此 mapper 开启二级缓存。

当 SqlSeesion 关闭时,会将数据存入到二级缓存.

MyBatis 架构

猜你喜欢

转载自blog.csdn.net/m0_56492261/article/details/129567410