1. MyBatis 简介
MyBatis 前身是apache的一个开源项目 iBatis , 2010 年这个项目迁移到了google code,改名为MyBatis 。2013年11月迁移到 Github 。 最新版本是Mybatis3。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
github地址:https://github.com/mybatis/
中文帮助文档:http://www.mybatis.org/mybatis-3/zh/index.html
2. 入门程序
-
准备工作
创建表、实体类、Mapper(即Dao层接口),实现查询全部班级信息。
CREATE DATABASE schools;
USE schools;
CREATE TABLE clses(
cid INT(10) AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(20)
);
INSERT INTO clses VALUES(DEFAULT, 'cls1901');
INSERT INTO clses VALUES(DEFAULT, 'cls1902');
INSERT INTO clses VALUES(DEFAULT, 'cls1903');
INSERT INTO clses VALUES(DEFAULT, 'cls1904');
INSERT INTO clses VALUES(DEFAULT, 'cls1905');
INSERT INTO clses VALUES(DEFAULT, 'cls1906');
COMMIT;
SELECT * FROM clses;
-
导入jar包
-
mapper.xml
一个Mapper对于一个xml映射文件,可以把映射文件想象成接口的实现类。
该映射文件需要放在classpath类路径下,一般放在mapper接口路径下。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入mapper.xml的dtd约束 -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace: 命名空间,写对应的Mapper接口的全路径 -->
<mapper namespace="com.bodhixu.mybatis.mapper.ClsMapper">
<!--
id:对应接口的方法名
resultType:返回集合中元素的数据类型
-->
<select id="queryAll" resultType="com.bodhixu.mybatis.bean.Cls">
<!-- 注意:sql语言不能加分号;结尾 -->
select * from clses
</select>
</mapper>
- mybatis.xml
Mybatis全局配置文件,需要放在classpath路径下,一般新建“source folder”。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入mybatis的dtd文件 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 注意:配置的顺序 -->
<configuration>
<!-- environments: 环境配置,内部可以配置多组环境。
后期与spring整合后,该配置被省略。
default:使用哪个id的开发环境
-->
<environments default="default">
<environment id="default">
<!-- 事务管理:原生JDBC -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源:数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/schools"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 注册mapper映射 -->
<mappers>
<!-- mapper resource:mapper.xml文件资源路径-->
<!-- <mapper resource="com/bodhixu/mybatis/mapper/ClsMapper.xml"/> -->
<!-- package:配置指定包下的映射文件 -->
<package name="com.bodhixu.mybatis.mapper"/>
</mappers>
</configuration>
- 执行测试
后期代码被Spring优化,可省略。
@Test
void testQueryAll() throws Exception {
//读取mybatis配置文件
InputStream is = getClass().getResourceAsStream("/mybatis.xml");
//创建Session工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
//创建SqlSession
SqlSession session = sessionFactory.openSession();
//创建Mapper
ClsMapper mapper = session.getMapper(ClsMapper.class);
//执行数据库操作
List<Cls> clses = mapper.queryAll();
for (Cls cls : clses) {
System.out.println(cls);
}
//关闭session
session.close();
}
3. MyBatis 体系架构
-
MyBatis 配置
SqlMapConfig.xml:mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml:sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
-
SqlSessionFactory
通过mybatis环境等配置信息构造SqlSessionFactory,即会话工厂。
-
sqlSession
由会话工厂创建sqlSession,即会话,操作数据库需要通过sqlSession进行。
-
Executor
mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
-
MappedStatement
MappedStatement 也是 mybatis 一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
-
输入映射
Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo。Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
-
输出映射
Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
4. 集成log4j
-
准备工作:设置.properties文件格式为"UTF-8"。
操作步骤:“ Windows–>Preferences–>General–>Content Types–>Text–>Java Propertied File–>修改Defaul encoding:UTF-8 ->点Update->applay and close” -
导入jar包, log4j-xx.jar
-
配置文件, log4j.properties,必须放在classpath类路径下,文件名不可以改变。
# 日志级别设置成ERROR,控制台输出CONSOLE,文件输出LOGFILE(如需要则添加)
log4j.rootCategory = ERROR, CONSOLE
# 对于mapper包下的logger级别设置成DEBUG
# 需要修改mapper包名
log4j.logger.com.bodhixu.mybatis.mapper = DEBUG
log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern = %C %d{yyyy-MM-dd HH:mm:ss} %m %n
log4j.appender.LOGFILE = org.apache.log4j.FileAppender
# 需要修改输出文件的路径
log4j.appender.LOGFILE.File = E:/my.log
log4j.appender.LOGFILE.Append = true
log4j.appender.LOGFILE.layout = org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern = %C %m %L %n
5. 全局配置文件
5.1 文档结构
配置文件的文档结构,必须按顺序配置
configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
5.2 properties(属性)
引入外部properties配置文件
<!--
properties: 引入外部properties配置文件
resource 引入类路径下资源
url 引入网络路径或磁盘路径下资源
-->
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
</environments>
5.3 settings(设置)
settings 运行时行为设置,比如mapUnderscoreToCamelCase,可以自动完成自动完成属性名称hotelName到数据库中字段hotel_name的映射。另外如果不符合规则映射失败,可以通过查询语句的列别名实现。
<settings>
<!-- 自动完成属性名称hotelName到数据库中字段hotel_name的映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<select id="queryAll2" resultType="com.bodhixu.bean.Cls2">
select c_id, c_name name from clses2
</select>
5.4 typeAliases(类型别名)
typeAliases,实现为java类型起别名。
- Mybatis默认别名
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
map | Map |
- 自定义类的别名
<typeAliases>
<!--
typeAliases 定义类的别名
type:java全类名
alias:自定义别名, 不区分大小写
-->
<typeAlias type="com.bodhixu.ssm.bean.Stu" alias="Stu"/>
</typeAliases>
- 为包下所有类定义别名
<typeAliases>
<!-- 为包下所有类设置别名,类别名默认为类名小写 -->
<package name="com.bodhixu.ssm.bean"/>
</typeAliases>
5.5 mappers(映射器)
mappers将sql映射映射到全局配置文件中
- 资源映射
<mappers>
<!-- resource: 引用类路径下文件 -->
<mapper resource="com/bodhixu/ssm/mapper/StuMapper.xml"/>
</mappers>
- 接口映射
<mappers>
<!--class 接口映射,注意:接口和映射文件必须同名,而且放在同一个路径里 -->
<mapper class="com.bodhixu.bean.Cls"/>
</mappers>
- 包映射
<mappers>
<!-- package 包映射。注意:接口和映射文件必须同名,而且放在同一个路径里 -->
<package name="com.bodhixu.ssm.mapper"/>
</mappers>
6. Mapper配置
6.1 resultType
mapper.xml中通过resultType属性设置查询操作的返回类型。如果是增、删、改操作则没有返回类型,因为都返回int,表示影响的行号。如果返回类型为集合,则resultType为集合中的泛型类型。
6.2 parameterType
mapper.xml中可以通过parameterType属性设置参数类型。
6.3 #{} 和 ${}
#{}
表示一个占位符号,可接收简单类型值或pojo属性值。如果接收简单类型值,#{}
括号中可以写value或其它名称。
Stu queryById(long sid) throws Exception;
<select id="queryById" resultType="com.bodhixu.ssm.bean.Stu" parameterType="long">
select * from stus where sid = #{sid}
</select>
${}
用于sql串拼接,可以接收简单类型值或pojo属性值。如果接收简单类型值,${}
括号中只能写value。
<select id="queryById" resultType="com.bodhixu.ssm.bean.Stu" parameterType="long">
select * from stus where sid = ${value}
</select>
6.4 模糊查询
模糊查询如果使用#{},传参时必须传字符串"%查询内容%",此时可以使用**’%${value}%’**,参数直接传查询内容即可。
//根据名字模糊查询
List<Stu> queryByName(String subName) throws Exception;
<select id="queryByName" resultType="stu">
select * from stus where name like '%${value}%'
</select>
6.5 多个简单类型参数的处理
-
方式1:通过索引取值
不能使用parameterType, 改用
#{index}
,是第几个参数就用第几个的索引,索引从0开始。
//查询年龄在指定范围的学生
List<Stu> queryByAge(int min, int max) throws Exception;
<!-- 多参数查询,通过索引取值 -->
<select id="queryByAge" resultType="stu">
select * from stus where age between #{0} and #{1}
</select>
-
方式2:将多参数封装成map格式的数据,通过Map的key取值
#{key}使用map中key的名字获得value值
//查询年龄在指定范围的学生
List<Stu> queryByAge2(Map<String, Integer> map) throws Exception;
<!-- 多参数查询,通过Map的key取值 -->
<select id="queryByAge2" resultType="stu">
select * from stus where age between #{min} and #{max}
</select>
- 方式3:通过参数注解
@Param
传值
//查询年龄在指定范围的学生
List<Stu> queryByAge3(@Param("m") int min, @Param("max") int max) throws Exception;
<!-- 多参数查询,通过参数注解@Param取值 -->
<select id="queryByAge3" resultType="stu">
select * from stus where age between #{m} and #{max}
</select>
6.6 删除数据
void deleteById(long sid) throws Exception;
<delete id="deleteById">
delete from stus where sid = #{sid}
</delete>
6.7 修改数据
void update(Stu stu) throws Exception;
<update id="update">
update stus set sname = #{sname}, sage = #{sage} where sid = #{sid}
</update>
6.8 插入数据
void insert(Stu stu) throws Exception;
<!-- 增、删、改的操作没有返回类型,因为默认都是返回int -->
<insert id="insert" parameterType="com.bodhixu.ssm.bean.Stu">
insert into stus values(seq_stus.nextval, #{name}, #{age}, #{birthday})
</insert>
//注意,默认操作未开始事务,必须手动提交
sqlSession.commit();
6.9 增删改的返回值和异常
可以返回void或者int。如果返回int,如果操作成功,返回的是受影响数据的数量。如果失败则抛出异常(如插入不允许重复的重复数据,或者删除有外键关联的数据)。
6.9 添加并返回自增主键
- 方法1:通过
slectkey
标签,查询自增主键
void insertGetKey(Stu stu) throws Exception;
<!-- 添加学生并且自增主键返回
selectKey:标签实现主键返回
keyColumn: 主键对应的列名
keyProperty: 主键对应pojo的属性名
resultType: 主键类型
order: 查询id的sql语句在insert操作之前或者之后执行
LAST_INSERT_ID():mysql的函数,返回auto_increment自增列新记录id值
-->
<insert id="insertGetKey" parameterType="com.bodhixu.ssm.bean.Stu">
<selectKey keyColumn="sid" keyProperty="sid" resultType="Long" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into stus(sname, sage, birthday) values(#{name}, #{age}, #{birthday});
</insert>
<!--oracle版本-->
<insert id="insertGetKey" parameterType="com.bodhixu.ssm.bean.Stu">
<!--在执行插入sql语句前,先查询下序列值,给sid赋值-->
<selectKey keyColumn="sid" keyProperty="sid" resultType="long" order="BEFORE">
select stus.nextval as sid from dual
</selectKey>
insert into stus values(#{sid}, #{name}, #{sage}, #{birthday});
</insert>
- 方法2:设置useGeneratedKeys属性,只适用于mysql
需要在全局配置文件中设置useGeneratedKeys为true
<settings>
<setting name="useGeneratedKeys" value="true"/>
</settings>
在xml映射文件中,同样设置useGeneratedKeys为true,并且指明主键名称
<insert id="insert" useGeneratedKeys="true" keyProperty="cid" keyColumn="cid" parameterType="com.bodhixu.mybatis.bean.Cls">
insert into cls(name, create_date) values(#{name}, #{createDate})
</insert>