JavaEE之MyBatis框架
一、MyBatis 简介
-
简介
MyBatis 是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

-
mybatis的功能架构
我们把Mybatis的功能架构分为三层:
-
API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
-
数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
-
基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
二、MyBatis 核心对象
-
SqlSession
使用 MyBatis 的主要 Java 接口就是 SqlSession。尽管你可以使用这个接口执行命令,获 取映射器和管理事务。我们会讨论 SqlSession 本身更多,但是首先我们还是要了解如果获取 一个 SqlSession 实例。SqlSessions 是由 SqlSessionFactory 实例创建的。SqlSessionFactory 对 象 包 含 创 建 SqlSession 实 例 的 所 有 方 法 。 而 SqlSessionFactory 本 身 是 由 SqlSessionFactoryBuilder 创建的,它可以从 XML 配置,注解或手动配置 Java 来创建 SqlSessionFactory。
-
SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 有五个 build()方法,每一种都允许你从不同的资源中创建一个 SqlSession 实例。
-
SqlSessionFactory build(InputStream inputStream)
-
SqlSessionFactory build(InputStream inputStream, String environment)
-
SqlSessionFactory build(InputStream inputStream, Properties properties)
-
SqlSessionFactory build(InputStream inputStream, String env, Properties props)
-
SqlSessionFactory build(Configuration config)
-
-
SqlSessionFactory
SqlSessionFactory 有六个方法可以用来创建 SqlSession 实例。默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:
-
会开启一个事务(也就是不自动提交)
-
连接对象会从由活动环境配置的数据源实例中得到。
-
事务隔离级别将会使用驱动或数据源的默认设置。
-
预处理语句不会被复用,也不会批量处理更新。
三、MyBatis XML配置
-
mybatis相关jar包

-
mybatisXML核心配置文件(mybatis-config.xml)
<?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>
<!--读取 db.properties-->
<properties resource="db.properties"></properties>
<!--配置 实体类的别名处理-->
<typeAliases>
<!--单独给实体类的起别名-->
<!-- <typeAlias type="cn.edu.dgut.pojo.User" alias="User"></typeAlias>-->
<!--直接扫描包-->
<package name="cn.edu.dgut.pojo"/>
</typeAliases>
<!--环境配置 -->
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"></transactionManager>
<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>
<!--将UserMapper.xml 和主配置文件关联-->
<mappers>
<mapper resource="cn/edu/dgut/pojo/UserMapper.xml"></mapper>
</mappers>
</configuration> -
数据库配置文件(db.properties)
#数据库驱动
jdbc.driver=com.mysql.jdbc.Driver
#数据库链接
jdbc.url=jdbc:mysql://localhost:3306/mybatisdemo?characterEncoding=utf8
#数据库账号
jdbc.username=root
#数据库密码
jdbc.password=123456
#jdbc.maxTotal=30
#jdbc.maxIdle=10
#jdbc.initialSize=5 -
日志配置文件(log4j.properties)
# 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
四、MyBatis XML映射文件
-
mybatis 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="curdUser">
<!--根据用户id查询,返回一个用户
SELECT * from tb_user -> List<User>
-->
<select id="selectUserById" parameterType="int" resultType="cn.edu.dgut.pojo.User">
select * from tb_user where userid=#{id}
</select>
<!--查询返回list 集合
SELECT * from tb_user -> List<User>
-->
<select id="selectUserList" resultType="User">
select * from tb_user
</select>
<!-- 模糊查询 根据用户名,返回list 集合 -->
<select id="selectUserByName" parameterType="String" resultType="User">
select * from tb_user where username like '%${value}%'
</select>
<!-- 插入数据 -->
<insert id="insertUser" parameterType="User">
insert into tb_user values (null,#{username},#{password})
</insert>
<!-- 更新数据 -->
<update id="updateUser" parameterType="User">
update tb_user set username=#{username},password=#{password} where userid=#{userid}
</update>
<!-- 删除数据 -->
<delete id="deleteUserById" parameterType="int">
delete from tb_user where userid=#{userid};
</delete>
</mapper>
-
获取SqlSession的工具类
public class MybatisUtil {
// 定义SessionFactory
private static SqlSessionFactory sessionFactory = null;
// 定义SqlSession
private static SqlSession sqlSession = null;
static {
InputStream is = null;
try {
// 读取核心mybatis配置文件(在内存中只是流的方式)
is = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSessionFactory对象,此对象可以完成对配置文件的读取
sessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
// 通过SqlSessionFactory获得一个SqlSession对象
public static SqlSession getSqlSession() {
// 返回SqlSession对象,该对象的作用是调用mapper文件进行数据操作(一定要先引mapper)
return sessionFactory.openSession();
}
// 如果SqlSession对象不为空,关闭它
public static void closeSession(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close();
}
}
}
-
实体类
public class User {
private int userid;
private String username;
private String password;
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
-
测试类
public class MybatisDemo01 {
五、MyBatis 动态SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解。MyBatis 3 大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
-
if
-
choose (when, otherwise)
-
trim (where, set)
-
foreach
if
动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
choose, when, otherwise
有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
trim, where, set
trim 元素的prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它带来的结果就是所有在 prefixOverrides 属性中指定的内容将被移除,并且插入 prefix 属性中指定的内容。
where 元素知道只有在一个以上的if条件有值的情况下才去插入"WHERE"子句。而且,若最后的内容是"AND"或"OR"开头的,where 元素也知道如何将他们去除。
set 元素会动态前置 SET 关键字,同时也会消除无关的逗号,因为用了条件语句之后很可能就会在生成的赋值语句的后面留下这些逗号。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<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>
<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>
foreach
动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。
<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>
六、MyBatis 逆向工程
mybatis需要程序员自己编写sql语句,而mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.java、mapper.xml、pojo…),可以让程序员将更多的精力放在繁杂的业务逻辑上。
-
mybatis逆向工程所需jar包

-
mybatis逆向工程配置文件(generator.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatisdemo?characterEncoding=utf8"
userId="root"
password="fzp666xfz888">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection> -->
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成实体类的位置 -->
<javaModelGenerator targetPackage="cn.edu.dgut.pojo"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀
