一. Mybatis 简述
MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由apache software foundation 迁移到了 google code, 并且改名为 MyBatis 。2013 年 11 月迁移到 Github。iBATIS 一词来源于“internet” 和“abatis” 的组合, 是一个基于 Java的持久层框架。
iBATIS 提供的持久层框架包括 SQL Maps 和 Data AccessObjects(DAO)MyBatis 是一个支持普通 SQL 查询, 存储过程和高级映射的优秀持久层框架。 MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索封装。 MyBatis 可以使用简单的 XML 或注解用于配置和原始映射, 将接口和 Java 的 POJO(Plain Old Java Objects, 普通的 Java 对象) 映射成数据库中的记录。
mybatis 不是一个完全的 orm 框架, Mybatis 需要程序员自己写 sql, 但是也存在映射(输入参数映射, 输出结果映射) , 学习门槛 mybatis 比hibernate 低; 同时灵活性高, 特别适用于业务模型易变的项目, 使用范围广。简单概括:更加简化 jdbc 代码,简化持久层,sql 语句从代码中分离,利用反射,将表中数据与 java bean 属性一一映射 即 ORM(Object RelationalMapping 对象关系映射)
使用范围:在日常的开发项目中, 如中小型项目, 例如 ERP,需求与关系模型相对固定建议使用 Hibernate, 对于需求不固定的项目, 比如: 互联网项目, 建议使用 mybatis, 因为需要经常灵活去编写 sql 语句。 总之, mybatis 成为当下必须学习掌握的一个持久层框架。
MyBatis 功能架构图:
从上面我们可以看到 mybatis 的功能架构分为三层:
API 接口层:提供给外部使用的接口 API,开发人员通过这些本地 API 来操纵数据库。接口层接收到调用请求就会调用数据处理层来完成具体的数据处理。
数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
MyBatis 框架体系结构:
二.Mybatis 环境搭建
1.新建 Maven 项目
新建 maven 项目 ,pom 文件添加依赖 jar
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- mybatis jar 包依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!-- log4j 日志打印 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
2.log4j 日志添加
在 src/main/resources 资源包下添加 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
3.resources 目录下主配置文件添加
新建 mybatis.xml 文件, 并加入配置信息如下(数据库名mybatis,表 user):
<?xml version="1.0" encoding="UTF-8" ?>
<!-- mybatis 框架头文件声明, 类似 spring 环境, 均需要加入头文件 -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 添加数据库连接相关配置信息 -->
<configuration>
<properties resource="jdbc.properties"></properties>
<typeAliases>
<!-- 配置别名 -->
<!--形式:
1. 通过xml
2. 通过注解
3. 扫描包
-->
<!-- 规则:
以类名首字母小写进行命名, User -> user
-->
<package name="com.shsxt.vo"/>
</typeAliases>
<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/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />-->
<!--里面的driver,url,username,password
为框架规定的名字,不能自定义,后面的名字对应properties文件的名字
-->
<property name="driver" value="${drive}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<!-- mapper 配置文件指定 文件数量可配置多个-->
<mappers>
<!--基于xml配置-->
<!--<mapper resource="com/shsxt/mapper/UserMapper.xml" />-->
<!--基于注解-->
<!--<mapper class="com.shsxt.mapper.UserMapper.xml"></mapper>-->
<!--包扫描-->
<package name="com.shsxt.mapper"/>
</mappers>
</configuration>
4.映射文件添加
新建 UserMapper.xml 配置文件
<?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">
<!--
1.命名空间配置 全局唯一 包名+文件名
2.配置 Mapped Statement
3. statement 配置
id 值声明 statement 编号 同一命名空间(同一文件)下不可重复
parameterType 输入参数即占位符的数据类型 类型可以是 基本数据类型,字符
串,java bean ,map,list 等
resultType 输出结果 类型可以是基本数据类型,字符串,java bean,map 等
statement 描述 即待执行的 sql
#{id} 占位符 变量名为 id/value 均可 ${value} 变量名必须为 value 字符
串拼接形式 无法避免 sql 注入
-->
<!--通过用户Id查询记录,where user_id=#{user_id}#里面的为形参,可为任意值-->
<mapper namespace="com.shsxt.mapper.UserMapper">
<!--通过名字查询某条记录-->
<select id="queryUserById" parameterType="int"
resultType="com.shsxt.vo.User">
select
user_id, user_name ,user_pwd from tb_user where user_id=#{user_id}
</select>
<!-- 通过名字和id查找 -->
<select id="queryUserByName" parameterType="string"
resultType="user">
select * from tb_user where user_name=#{user_name}
</select>
<!-- 通过用户查找 -->
<select id="queryUserByNameAndId" parameterType="map"
resultType="user">
select * from tb_user where user_name=#{user_name} and user_id=#{user_id}
</select>
<!-- 查找用户总数-->
<select id="queryUserByUser" parameterType="user">
select * from tb_user where user_name=#{user_name} and user_id=#{user_id}
</select>
<!-- 添加不返回ID -->
<select id="queryUserTotal" resultType="int">
select count(1) from tb_user
</select>
<!-- 添加记录返回ID -->
<insert id="addUser" parameterType="user" useGeneratedKeys="true" keyProperty="user_id">
insert into tb_user (user_name, user_pwd, user_age)
values (#{user_name}, #{user_pwd}, #{user_age})
</insert>
<!-- 添加一条记录返回ID -->
<insert id="addUserReturnId" parameterType="list" useGeneratedKeys="true" keyProperty="user_id">
insert into tb_user (user_name, user_pwd, user_age)
values (#{item.user_name}, #{item.user_pwd}, #{item.user_age})
</insert>
<!-- 批量添加记录返回ID -->
<insert id="addUserBatchReturnId" parameterType="list" useGeneratedKeys="true" keyProperty="user_id">
insert into tb_user (user_name, user_pwd, user_age)
values
<foreach collection="list" item="item" separator=",">
(#{item.user_name}, #{item.user_pwd}, #{item.user_age})
</foreach>
</insert>
<!-- 更新 -->
<update id="updateUser" parameterType="user" useGeneratedKeys="true" keyProperty="user_id">
update tb_user set user_name=#{user_name}, user_pwd=#{user_pwd},user_age=#{user_age}
where user_id=#{user_id}
</update>
<!-- 批量更新密码 -->
<update id="updateUserPwdBatch">
update tb_user set user_pwd=888888
where user_id between
<foreach collection="array" item="item" separator="and">
#{item}
</foreach>
</update>
<!-- 删除,根据Id -->
<delete id="deleteUser" parameterType="int">
delete from tb_user where user_id = #{user_id}
</delete>
<!-- 批量删除,根据Id -->
<delete id="deleteUserBatch" parameterType="list">
delete from tb_user where user_id in (
<foreach collection="array" item="item" separator=",">
#{item}
</foreach>
)
</delete>
<!--___________使用SQL片段方法_________________-->
<resultMap id="userMap" type="user">
<id column="user_id" property="user_id"></id>
<result column="user_name" property="user_name"></result>
<result column="user_pwd" property="user_pwd"></result>
<result column="user_age" property="user_age"></result>
</resultMap>
<sql id="base">
user_id, user_name, user_pwd, user_age
</sql>
<select id="queryUserByParams" parameterType="string" resultMap="userMap">
select <include refid="base"/> from tb_user
where user_name like concat('%',#{user_name},'%')
</select>
</mapper>
修改 pom 配置,设置资源文件夹路径
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
5.测试
//定义个UserMapperImpl类型的实例
private UserMapperImpl userMapper;
//before相当于全局变量,提前加载
@Before
public void before() throws IOException {
//得到输入流
InputStream inp = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inp);
//得到实例
userMapper = new UserMapperImpl(sqlSessionFactory);
}
@Test
public void queryUserById(){
User user = userMapper.queryUserById(1);
System.out.println(user);
}
三.Mybatis 配置文件解释
1.typeAliases:
类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。例如:Configuration 标签下添加
<typeAliases>
<typeAlias alias="User" type="com.shsxt.mybatis.vo.User" />
</typeAliases>
修改 UserMapper.xml 文件
<mapper namespace="com.shsxt.mybatis.mapper.UserMapper">
<select id="queryUserById" parameterType="int "resultType="User">
select id,userName,userPwd from user where id=#{id}
</select>
</mapper>
也可以指定一个包名(大家最喜欢的方式),MyBatis 会在包名下面搜索需要的 JavaBean,也可以指定一个包名(大家最喜欢的方式),MyBatis 会在包名下面搜索需要的 JavaBean,比如:
<typeAliases>
<!-- <typeAlias alias="User" type="com.shsxt.mybatis.vo.User" /> -->
<package name="com.shsxt.mybatis.vo"/>
</typeAliases>
2.typeHandlers 类型处理器
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java类型。下表描述了一些默认的类型处理器。
3.配置环境(environments) 配多个数据源(数据库)
MyBatis 可以配置成适应多种环境, 这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。 例如, 开发、 测试和生产环境需要有不同的配置; 或者共享相同 Schema 的多个生产数据库, 想使用相同的 SQL 映射。 许多类似的用例。不过要记住: 尽管可以配置多个环境, 每个 SqlSessionFactory 实例只能选择其一。所以, 如果你想连接两个数据库, 就需要创建两个 SqlSessionFactory 实例, 每个数据库对应一个。 而如果是三个数据库, 就需要三个实例, 依此类推, 记起来很简单:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver2}" />
<property name="url" value="${url2}" />
<property name="username" value="${username2}" />
<property name="password" value="${password2}" />
</dataSource>
</environment>
</environments>
## development
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncodi
ng=utf8
username=root
password=root
## test
driver2=com.mysql.jdbc.Driver
url2=jdbc:mysql://127.0.0.1:3306/mybatis2?useUnicode=true&characterEnco
ding=utf8
username2=root
password2=root
4.mappers 映射器(四种配置)
这里是告诉 mybatis 去哪寻找映射 SQL 的语句。可以使用类路径中的资源引用,或者使用字符,输入确切的 URL 引用。这些配置会告诉了 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件。
<!— sqlmapper 配置文件路径 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!—url 绝对路径形式-->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!—接口 列表配置形式 注解 sql-->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!—映射包下所有接口-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
第四种最常用,做简单.
四.Mapper Xml 映射文件
1.Select 元素标签使用
<!--通过用户Id查询记录,where user_id=#{user_id}#里面的为形参,可为任意值-->
<mapper namespace="com.shsxt.mapper.UserMapper">
<!--通过名字查询某条记录-->
<select id="queryUserById" parameterType="int"
resultType="com.shsxt.vo.User">
select
user_id, user_name ,user_pwd from tb_user where user_id=#{user_id}
</select>
<!-- 通过名字和id查找 -->
<select id="queryUserByName" parameterType="string"
resultType="user">
select * from tb_user where user_name=#{user_name}
</select>
</mapper>
2.Insert 元素标签使用
<mapper namespace="com.shsxt.mapper.UserMapper">
<!-- 批量添加记录返回ID -->
<insert id="addUserBatchReturnId" parameterType="list" useGeneratedKeys="true" keyProperty="user_id">
insert into tb_user (user_name, user_pwd, user_age)
values
<foreach collection="list" item="item" separator=",">
(#{item.user_name}, #{item.user_pwd}, #{item.user_age})
</foreach>
</insert>
</mapper>
3.Update 元素标签使用
<mapper namespace="com.shsxt.mapper.UserMapper">
<!-- 批量更新密码 -->
<update id="updateUserPwdBatch">
update tb_user set user_pwd=888888
where user_id between
<foreach collection="array" item="item" separator="and">
#{item}
</foreach>
</update>
</mapper>
4.Delete 元素标签使用
<mapper namespace="com.shsxt.mapper.UserMapper">
<!-- 批量删除,根据Id -->
<delete id="deleteUserBatch" parameterType="list">
delete from tb_user where user_id in (
<foreach collection="array" item="item" separator=",">
#{item}
</foreach>
)
</delete>
</mapper>
5.choose, when, otherwise 选择器使用
我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句
select id="queryUserByParams" parameterType="map" resultType="user">
select id,userPwd
<choose>
<when test="nation!=null and nation!=''">
,userName
</when>
<otherwise>
,realName
</otherwise>
</choose>
from user
where userName like '%${userName}%'
<if test="phone!=null and phone!=''">
and phone like '%${phone}%'
</if>
</select>
6.trim, where, set
对于 update 语句, 我们采用<set></set>去设置值,去除最后一个条件的逗号:
<!--通过名字与年龄查询 __ set的使用-->
<select id="updateUserByNameAndId_set" parameterType="list">
update tb_user
<set>
<if test="@Ognl@isNotEmpty(user_name)">
user_name=#{user_name},
</if>
<if test="@Ognl@isNotEmpty(user_age)">
user_age=#{user_age},
</if>
</set>
where user_id = #{user_id}
</select>
where 元素知道只有在一个以上的 if 条件有值的情况下才去插入“WHERE”子句。 而且,若最后的内容是“AND”或“OR”开头的, where 元素也知道如何将他们去除。
<!--通过名字与年龄查询 __ where的使用-->
<select id="queryUserByNameAndId_where" parameterType="user" resultMap="userMap">
select * from tb_user
<where>
<if test="@Ognl@isNotEmpty(user_name)">
user_name like concat('%',#{user_name},'%')
</if>
<if test="@Ognl@isNotEmpty(user_age)">
and user_age like concat('%',#{user_age},'%')
</if>
</where>
</select>
如果 where 元素没有按正常套路出牌, 我们还是可以通过自定义 trim 元素来定制我们想要的功能。 比如, 和 where 元素等价的自定义 trim 元素为:
<!--通过名字与年龄查询 __ trim的使用-->
<select id="queryUserByNameAndId_trim" parameterType="user" resultMap="userMap">
select * from tb_user
<trim prefix="where" prefixOverrides="and|or">
<if test="@Ognl@isNotEmpty(user_name)">
user_name like concat('%',#{user_name},'%')
</if>
<if test="@Ognl@isNotEmpty(user_age)">
and user_age like concat('%',#{user_age},'%')
</if>
</trim>
</select>
功能性:trim>where and set(上面代码的@Ognl@isNotEmpty(user_name)为一个工具类,调用里面的静态方法),里面的if或foreach可以实现动态的SQL语句.