mybatis
1、什么是mybatis?
MyBatis 是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
2、mybatis的入门案例
2.1、导入mybatis依赖坐标(版本选用3.4.6)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
2.2、配置mybatis核心映射文件
/*导入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>
<!--映射连接数据库配置文件-->
<properties resource="jdbc.properties"/>
<!--配置连接环境-->
<environments default="mysql">
<environment id="mysql">
<!--配置事务管理器-->
<transactionManager type="JDBC"/>
<!--声明连接池类型(此处是mybatis中自带的POOLED连接池)-->
<dataSource type="POOLED">
<!--配置连接连接数据库的四项基本信息(此处使用properties文件引入)
"${}"el表达式
-->
<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>
<!--配置操作数据语句的xml映射文件-->
<mappers>
<mapper resource="com/wql/IEmpMapper.xml"/>
</mappers>
</configuration>
2.3、配置Mapper映射文件,该配置文件主要配置对应的SQL语句
<!--导入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">
<!--namespace:属性映射到具体的接口的全限定类名,用于查找操作对应的SQL的方法-->
<mapper namespace="com.wql.mapper.IEmpMapper">
//配置字段与属性对应,type属性:所属数据类型
<resultMap id="empResultMap" type="emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hireDate"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<result column="deptno" property="deptno"/>
</resultMap>
<!--resultMap:标签的作用:对应当数据库字段与实体类属性名不一致时,可以使用resultMap标签进行配置-->
<select id="findEmpList" resultMap="empResultMap">
select * from emp;
</select>
</mapper>
2.4、通过SqlSession对象获取具体操作的Bean对象
//加载xml核心配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//通过工厂构建者对象获取工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//通过工厂对象获取Sqlsession对象
//此处openSession()方法中设为true为自动提交事务,默认为false
SqlSession sqlSession = factory.openSession();
//使用sqlsesstion对象对象调用getBean方法获取Maapper对象
IEmpMapper mapper = sqlSession.getMapper(IEmpMapper.class);
List<Emp> empList = mapper.findEmpList();
//遍历输出结果
for (Emp emp : empList) {
System.out.println(emp);
}
2.5、补充项:注解形式代替mapper.xml配置文件实现
package org.mybatis.example;
public interface BlogMapper {
//配置注解形式,再注解关键字中输入对应查询sql语句即可!
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
3、mybatis中三大类
3.1、SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例
3.2、使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域(使用单例模式创建sqlsessionfactory工厂)
3.3、SqlSession:每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行
4、mybatis中的配置
4.1、properties属性:
<!--properties属性配置连接DB时,属性名称对应值-->
<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>
4.2、类型别名:typeAliases
设定了类型别名时,当再type属性中设置数据类型时,直接给定类名并且首字母小写
<!--给类路径设置别名-->
<typeAliases>
<package name="com.wql.entity"/>
</typeAliases>
<!--给定变量数据类型时,直接指定类名并且首字母小写-->
<resultMap id="empResultMap" type="emp"/>
4.3、环境配置:environments
尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
<environments default="mysql">
<!--transactionManager:事务管理器-->
<environment id="mysql">
<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>
4.4、映射器:mappers
映射器就是告诉mybatis需要去哪里寻找sql的配置文件信息;
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="com/wql/IEmpMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="com.wql.mapper.IUserMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="com.wql.mapper"/>
</mappers>
5、xml映射文件
5.1、select:sql查询语句对应标签
<!--id:一般对应接口中的方法名
parameterType:方法中呦形参时,对应的形参类型
resultMap:查询结果集返回的数据类型
#{ }:表示占位符:?
-->
<select id="findEmpList" parameterType="int" resultMap="empResultMap">
select * from emp where id = #{id};
</select>
5.2、insert, update 和 delete
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
5.3、获取自动生成的id主键
<!--方式一:通过开启主键自动回填方式获取主键-->
<!--<insert id="addEmp" parameterType="emp" useGeneratedKeys="true" keyProperty="empno">
insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)
value (#{ename},#{job},#{mgr},#{hireDate},#{sal},#{comm},#{deptno})
</insert>-->
<!--方式二:更灵活的获取自增的主键-->
<!--order="AFTER":在下边sql语句执行之后执行的语句
keyProperty:声明哪个是自动增长的主键
resultType:主键对应的数据类型
select last_insert_id():该语句获取自定增长的主键
-->
<insert id="addEmp" parameterType="emp">
<selectKey order="AFTER" keyProperty="empno" resultType="int">
select last_insert_id();
</selectKey>
insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)
value (#{ename},#{job},#{mgr},#{hireDate},#{sal},#{comm},#{deptno})
</insert>
5.4、${}与#{}的区别
#{}:相当于在premeterStatement中使用的占位符?表示;该做法较为安全,防止sql注入问题;
${}:mybatis不会解析成占位符,而是直接使用字符串拼接的形式将变量传如到插入的SQL语句中
例如:ORDER BY ${columnName}
当sql语句中的数据是动态的数据,例如列名或表名时,此时更适合使用${}来表示;
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);
@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);
5.5、高级结果映射
association与collection
<resultMap id="empResultMap" type="emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hireDate"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<result column="deptno" property="deptno"/>
<!--在一对一以及多对一的查询中使用association标签对结果映射的封装-->
<association property="emp" javaType="emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
</association>
</resultMap>
<resultMap id="findDept" type="dept">
<id column="deptno" property="deptno"/>
<result column="dname" property="dname"/>
<result column="loc" property="loc"/>
<!--在一对多或多对多的结果集封装时,使用collection标签-->
<collection property="empList" ofType="emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hireDate"/>
<result column="sal" property="sal"/>
<result column="comm" property="comm"/>
<result column="deptno" property="deptno"/>
</collection>
</resultMap>
5.6、缓存
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
<cache/>
6、动态sql
-
if
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分
<select id="findUserById" resultType="user">
SELECT * FROM t_user
WHERE id = #{id}
<if test="username != null">
AND username like #{username}
</if>
</select>
-
trim、where、set
where标签可以代替sql中的where关键子,并消除and关键字
<select id="findUserById" resultType="Blog"> SELECT * FROM t_user <where> <if test="username != null"> username = #{username} </if> <if test="password != null"> AND password like #{password} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> </select>
set 元素可以用于动态包含需要更新的列,忽略其它不更新的列;可以代替set关键字并消除多余的,符号!
<update id="updateUser">
update t_user
<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与where的结合使用;prefix:前缀 suffixOverrides:后缀
<trim prefix="SET" suffixOverrides=",">
...
</trim>
-
foreach遍历结果
<select id="selectUserByIds" resultType="user"> SELECT * FROM t_user u WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>