目录
什么是MyBatis?
MyBatis 本是 apache 的一个开源项目 Ibatis,2010年这个项目由 apache software foundation 迁移到了google code,并且改名为 MyBatis 。2013年11月迁移到 Github。
Ibatis 一词来源于 internet 和 abatis 的组合,是一个基于 Java 的持久层框架。Ibatis 提供的持久层框架包括 SQL Mapps 和 Data Access Objects(DAO)
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索封装。MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
每个 MyBatis 应用程序主要都是使用 SqlSessionFactory 实例的,一个 SqlSessionFactory 实例可以通过 SqlSessionFactoryBuilder 获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。
用 xml 文件构建 SqlSessionFactory 实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpath resource),但你可以使用任何 Reader 实例,包括用文件路径或file://开头的url创建的实例。MyBatis 有一个实用类----Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。
MyBatis 最强大的特性之一就是它的动态语句功能。如果您以前有使用 JDBC 或者类似框架的经历,您就会明白把 SQL 语句条件连接在一起是多么的痛苦,要确保不能忘记空格或者不要在 columns 列后面省略一个逗号等。动态语句能够完全解决掉这些痛苦。尽管与动态 SQL 一起工作不是在开一个 party,但是MyBatis 确实能通过在任何映射 SQL 语句中。
ORM 简介
对象关系映射(Object Relational Mapping,简称 ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。mybatis 就是全国使用最多的 orm 框架。
简单实现 mybatis
1.环境搭建
创建 maven web 项目 mybatis01 并添加 maven 依赖如下。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.6</version>
</dependency>
2.配置核心配置文件
配置 mybatis 核心配置文件:mybatis-conf.xml,在 resource 目录下创建此文件,内容如下:
<?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>
<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="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/PetMapper.xml"></mapper>
</mappers>
</configuration>
注意:
dataSource 的类型可以配置成其内置类型之一, UNPOOLED、POOLED 、JNDI。
- UNPOOLED,MyBatis 会为每一个数据库操作创建一个新的连接,并关闭它。该方式适用于只有小规模数量并发用户的简单应用程序上。
- POOLED,MyBatis 会创建一个数据库连接池,连接池中的一个连接将会被用作数据库操作。一旦数据库操作完成,MyBatis 会将此连接返回给连接池。在开发或测试环境中,经常使用此种方式。
- JNDI,MyBatis 从在应用服务器向配置好的 JNDI 数据源 dataSource 获取数据库连接。在生产环境中,优先考虑这种方式。
3.日志配置(可不配置)
为了监控 mybatis 执行情况,我们通过 logback 打印相关程序运行情况。在 resource 下添加日志配置文件 logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p --- [%t] %-40.40logger{39} : %m%n</pattern>
</encoder>
</appender>
<!--根logger-->
<root level="DEBUG" additivity="false">
<appender-ref ref="console"/>
</root>
</configuration>
加入该文件后,mybatis 运行情况、发送的 SQL、SQL 填充的数据和返回的数据条数都打印显示到控制台。
4.创建实体
创建对应实体,并添加对应的 getter 与 setter 方法。因为 mybatis 会使用反射完成对象的封装,所以实体一定需要无参构造方法。如果需要输出对象,还需要重写它的 toString 方法
public class Pet{
private Integer id;
private String name;
private Double weight
}
5.创建 Mapper 文件
mybatis 的所有数据库操作都是通过 mapper 文件完成的。mapper 文件一般存放在 resource/mapper/ 目录下。
创建实体类对应的映射文件 *Mapper.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">
<mapper namespace="cn.hx.mapper">
<select id="getById" parameterType="int" resultType="cn.hx.Pet">
select * from pet where id=#{id}
</select>
</mapper>
注意:
parameterType:参数类型
resultType:方法返回类型(如果返回是集合,则返回类型添集合存放对象的类型的全路径)
不论是参数类型还是返回类型,自定义类都需要写类的全路径名。
6.注册 mapper 文件
在 mybatis 核心配置文件 mybatis-conf.xml 中注册上面的 *Mapper.xml
<mappers>
<mapper resource="mapper/PetMapper.xml"></mapper>
</mappers>
下面是对这几个配置文件一点解释说明:
1、配置文件 mybatis-conf.xml 是 mybatis 用来建立 sessionFactory,里面主要包含了数据库连接相关内容。
2、mybatis-conf.xml 里面的 是包含要映射的类的 xml 配置文件。
3、在 *Mapper.xml 文件里面主要是定义各种 SQL 语句,以及这些语句的参数,以及要返回的类型等等。
7.运行测试
创建 main 方法并完成相关测试
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
public class MainTest {
public static void main(String[] args) throws IOException {
//加载 mybatis 的核心配置文件(它也加载关联的映射文件)
Reader reader = Resources.getResourceAsReader("mybatis-conf.xml");
//构建 sqlSession 的工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建能执行映射文件中 sql 的 sqlSession
SqlSession session = sessionFactory.openSession();
Object o = session.selectOne("cn.hx.mapper.petMapper.getById",3);
System.out.println(o);
}
}
注意:
1.selectOne 设计的初衷是查询单个,当查询时出现多个结果会报下面的错误:如果查询出来是集合用 selectList 方法。
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
2.SqlSessionFactory 线程安全性,可以设计成单例
3.SqlSession 线程非安全,不能做类的公用变量
接口注解
在上一节中实现了 mybatis 的一个简单的查询,还有更简单的方法,使用合理描述参数和 SQL 语句返回值的接口(比如:IUserMapper.java),这样现在就可以不使用类似 UserMapper.xml 配置文件,至此更简单,代码更安全,不容易发生的字符串文字和转换的错误,下面是项目创建的详细过程:
创建一个接口:PetMapper,并在其中声明对应的操作方法
public interface PetMapper {
@Insert("insert into pet(name,weight) values (#{name},#{weight})")
int add(Pet pet);
@Select("select * from pet where id=#{id}")
Pet getById(int id);
}
在 mybatis-conf.xml 里面注册 mapper 接口
<mapper class="cn.hx.mybatis.mapper.PetMapper"></mapper>
测试类修改下面的位置完成测试
public static void main(String[] args) throws IOException {
//加载mybatis的配置文件(它也加载关联的映射文件)
Reader reader = Resources.getResourceAsReader("mybatis-conf.xml");
//构建sqlSession的工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建能执行映射文件中sql的sqlSession
SqlSession session = sessionFactory.openSession();
//映射sql的标识字符串
//执行查询返回一个唯一user对象的sql
Pet pet = session.getMapper(PetMapper.class ).getById( 1 );
//根据 mapper 的 namespace 和 id 调用方法
System.out.println(pet);
}
至此,基于接口注解的查询方式完成,使用注解时 SQL 很难动态,所以最常用的是接口与 xml 结合使用。
注意:在执行数据库增删改操作时 session 默认是不自动提交的。需要手动调用 session.commit();提交操作。
接口与 xml 结合使用
在实际开发中使用比较多的是接口与 xml 结合使用,这样既可以降低编写 statement 时使用字符串容易出错的概率,同时 xml 在编译过后里面的内容还是原样显示,方便后期的 SQL 优化。最后使用接口和 xml 结合的方式也体现 java 程序的高内聚低耦合特性。使用 接口与 xml 结合使用需要在 mybatis-conf.xml 里面注册对应用到的 xml。
<mappers>
<mapper resource="mapper/PetMapper.xml"></mapper>
</mappers>
Mapper.xml 里面的 的 namespace 指向接口的类路径,同时接口里面的方法和 xml 里面的 id 对应。
调用时还是通过接口调用,但是接口的注解需要全部去掉。
PetDao mapper = session.getMapper(PetDao.class);
System.out.println(mapper.queryById(87));
这样我们就可以使用 mybatis 的动态 SQL,又可以通过接口调用,减少书写错误的可能。
数据表的基本操作
通过接口与 Mapper.xml 结合的方式可以很好的完成数据库的各种操作。在 mapper.xml 里面加入对应的 CRUD 的语句与接口中的方法名对应即可完成相关操作,对应的 mapper.xml 可以使用 insert、delete、update、select 等节点完成相应的操作,同时指定相应的参数类型和返回类型。
<insert id="insert" parametertype="cn.hx.entity.Pet">
insert into pet(name,weight) values(#{name},#{weight})
</insert>
<delete id="delete" parametertype="int">
delete from pet where id=#{id}
</delete>
<select id="getById" parametertype="int" resulttype="cn.hx.entity.Pet">
select * from pet where id=#{id}
</select>
<select id="selectAll" resulttype="cn.hx.entity.Pet">
select * from pet
</select>
注意:SQL 中含有特殊字符使用 CDATA 标签
weight <![CDATA[<]]> 10
注意:
- xml 的 id 对应接口的方法名。
- 除了查询方法以外其它方法都必须添加事务
SqlSession session = sessionFactory.openSession();
session.getMapper( UserMapper.class ).insertUser( new User( "222",1 ) );
session.commit();
session 有对应的提交与回滚的方法
或者获取 session 时就让 session 自动提交
SqlSession session = sessionFactory.openSession(true);
优化连接配置文件与别名管理器
数据库连接信息专门放到一个文件中
resource 下创建 db.properties 文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
jdbc.username=root
jdbc.password=123456
修改配置文件
<properties resource="db.properties">
<property name="driver" value="${jdbc.driverClassName}">
<property name="url" value="${jdbc.url}">
<property name="username" value="${jdbc.username}">
<property name="password" value="${jdbc.password}"></property>
</properties>
别名管理器
为实体类定义别名,简化 sql 映射 xml 文件中的引用,在 mybatis-conf.xml 文件加入
<typealiases>
<typealias type="cn.hx.entity.Pet" alias="pet"></typealias>
</typealiases>
type:指定要起别名的类型全类名,默认别名就是类名(不区分大小写);
alias:指定新的别名
这样,使用时使用别名即可操作数据库
<select id="selectById" parametertype="int" resulttype="pet">
select * from pet where id=#{id}
</select>
typealiases 批量起别名
package:为某个包下的所有类批量起别名。
<typealiases>
<package name="cn.hx.ibatis.bean"></package>
</typealiases>
name:为当前包以及下面所有的后代包的每一个类都起一个默认别名(与类名相同且不区分大小写)
批量起别名的情况下,使用 @Alias 注解为某个类型指定新的别名。
mybatisX 插件
功能
1.mapper 接口与 xml 来回跳转。
2.mapper 方法自动生成 xml。
3.xml 校验 id 是否与接口方法名一致。
下载:
插入数据后获取自增 id
在开发中经常需要获取插入数据的自增 id,mybatis 底层会使用 jdbc 将获取到的 id 设置到参数对象中。配置如下:
<insert id="add" parameterType="cn.hx.Pet" keyProperty="id" useGeneratedKeys="true">
在执行完插入语句后该实体的 id 便不再为空。
keyProperty:表示返回的 id 要保存到对象的那个属性中
useGeneratedKeys:表示主键 id 为自增长模式
全 map 操作
有时在开发中,由于数据库结构经常发生变化或开发人员为了图方便不创建实体,也就是在属性全部都使用 map 传输。
在使用 map 时注意将原来的实体位置全部换成 map 即可,一个对象对应一个 map。
接口改造:
import java.util.List;
import java.util.Map;
public interface PetMapper {
int insert(Map map);
List<map> selectAll();
}
xml 改造:
<insert id="insert" parametertype="map">
insert into pet(name, weight) values(#{name}, #{weight})
</insert>
<select id="selectAll" resulttype="map">
select * from pet
</select>
使用 map 极大的影响程序正确率与可读性。虽然这种操作并不是 java 程序设计者建议使用的,但是还是有很多程序员违规使用。