MyBatis官方文档:https://mybatis.org/mybatis-3/zh/index.html
Maven依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
既可引入外部配置文件也可内部配置
config.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=123456
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
...
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
加载顺序,后加载的覆盖先加载的
为每个类设置别名
<typeAliases>
<typeAlias type="com.pojo.User" alias="User"/>
</typeAliases>
指定包名,没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名
<typeAliases>
<package name="com.pojo"/>
</typeAliases>
内置别名
_int
对应 int
int
对应 Integer
引入资源方式
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!--
使用映射器接口实现类的完全限定类名
需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!--
将包内的映射器接口实现全部注册为映射器
但是需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
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="com..mapper.UserMapper">
</mapper>
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
所有学生(Student)对应同一个老师(Teacher)
<select id="getStudents" resultMap="StudentTeacher" >
select s.id sid, s.name sname , t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher" type="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<!--关联对象property 关联对象在Student实体类中的属性-->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
column="{key=value,key=value}"
其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
-->
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
一个老师拥有多个学生
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname , t.name tname, t.id tid
from student s,teacher t
where s.tid = t.id and t.id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
<select id="getTeacher" resultMap="TeacherStudent">
select * from teacher where id = #{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<!--column是一对多的外键 , 写的是一的主键的列名-->
<collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{id}
</select>
<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
trim定制成where
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
trim定制成set
<trim prefix="SET" suffixOverrides=",">
...
</trim>
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT * FROM POST P WHERE ID in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
//Results可以用id命名,这里命名为studentMap,在其他方法中可以直接调用
@Select("select * from student")
@Results(id = "studentMap",value = {
@Result(id=true,column = "sid",property = "sid"),
@Result(column = "sname",property = "sname"),
@Result(column = "sex",property = "sex")
})
List<Student> findAll();
//直接调用已有的映射
@Select("select * from student where sid=#{id}")
@ResultMap("studentMap")
Student findById(Integer integer);
插入数据后返回id问题,两种方式
options,添加表的列名sid,指定成员变量的名id,设置useGeneratedKeys = true
selectkey,基本的思路和xml配置一样,代码编写如下:
@Insert("insert into student(sname,sex,birthday,cno) values(#{name},#{sex})")
//@Options(useGeneratedKeys = true,keyColumn = "sid",keyProperty = "id")
@SelectKey(statement = "select last_insert_id()",keyProperty = "id", keyColumn = "sid",resultType = int.class,before = false)
void addStudent(Student student);
@One 注解(一对一)代替了
<assocation>
标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
使用格式:@Result(column=" ",property="",one=@One(select=""))
@Select("select * from account")
@Results(id="accountMap",
value= {
@Result(id=true,column="id",property="id"),
@Result(column="uid",property="uid"),
@Result(column="money",property="money"),
@Result(column="uid",
property="user",
one=@One(select="com.dao.IUserDao.findById",
fetchType=FetchType.LAZY)
)
})
List<Account> findAll();
@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);
@Many 注解(多对一)代替了
<Collection>
标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;
使用格式:@Result(property="",column="",many=@Many(select=""))
@Select("select * from user")
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="id",property="accounts",
many=@Many(
select="com.dao.IAccountDao.findByUid",
fetchType=FetchType.LAZY
)
)
})
List<User> findAll();
说明:
@Many:
相当于<collection>的配置
select 属性:代表将要执行的 sql 语句
fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值
@Select("select * from account where uid = #{uid} ")
List<Account> findByUid(Integer userId);
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}
要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:
@Update({"<script>",
"update Author",
" <set>",
" <if test='username != null'>username=#{username},</if>",
" <if test='password != null'>password=#{password},</if>",
" <if test='email != null'>email=#{email},</if>",
" <if test='bio != null'>bio=#{bio}</if>",
" </set>",
"where id=#{id}",
"</script>"})
void updateAuthorValues(Author author);
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog
<where>
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="if-title-author"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</where>
</select>
SqlSession级别的缓存,也称为本地缓存,默认开启
clearCache()
在配置文件中开启全局缓存 【mybatis-config.xml】
<setting name="cacheEnabled" value="true"/>
在需要的mapper.xml中配置使用二级缓存【xxxMapper.xml】
<cache/>
配置二级缓存
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
解除SQL和代码的耦合,提供xml标签,支持编写动态SQL,支持对象与数据库的字段关系映射
#{}
是预编译处理,${}
是字符串替换#{}
时,会将SQL中的#{}
替换为?号,调用PreparedStatement的set方法赋值,防止SQL注入${}
时,直接将${}
替换成变量的值%
${...}
:like ‘%${value}%‘
#{...}
:"%"#{value}"%"
Mapper 接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回。
如果采用主键自增长策略,自动生成的键值在insert执行完后被设置到传入的参数对象中,需要加上配置:
<insert id=”insertname” usegeneratedkeys=”true” keyproperty=”id”>
顺序传参
public User selectUser(String name, int deptId);
<select id="selectUser" resultMap="UserResultMap">
select * from user where user_name = #{0} and dept_id = #{1}
</select>
@Param注解传参
public User selectUser(@Param("userName") String name, @Param("deptId") int deptId);
<select id="selectUser" resultMap="UserResultMap">
select * from user where user_name = #{userName} and dept_id = #{deptId}
</select>
Map传参
public User selectUser(Map<String, Object> params);
<select id="selectUser" parameterType="map" resultMap="UserResultMap">
select * from user where user_name = #{userName} and dept_id = #{deptId}
</select>
Java Bean传参
public User selectUser(User user);
<select id="selectUser" resultMap="UserResultMap">
select * from user where user_name = #{UserName} and dept_id = #{deptId}
</select>
SqlSession交给了Spring管理,Spring在使用完后就会关闭
二级缓存是mapper级别,当不同的mapper操作同一个数据时就会产生数据不一致
参考文章:MyBatis原理分析(通俗易懂)
原文:https://www.cnblogs.com/yxmhl/p/11787826.html