MyBatis
简介
- ORM : 对象关系映射(Object RelationShip Mapping)
- MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
- iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBaties提供的持久层框架包括SQL Maps和Data Access Objects(sDAO)
官网
- Maven项目不用下载jar包
- mybaits的代码由github.com管理,下载地址:https://github.com/mybatis/mybatis-3/releases
- 官方文档:https://mybatis.org/mybatis-3/zh/index.html
概述
- MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- MyBatis主要就完成2件事情
- 封装JDBC操作
- 利用反射打通Java类与SQL语句之间的相互转换
- MyBatis的主要设计目的就是让我们对执行SQL语句时对输入输出的数据管理更加方便,所以方便地写出SQL和方便地获取SQL的执行结果才是MyBatis的核心竞争力。
特点
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的ORM字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql
体系结构
- mybatis配置文件,包括
Mybatis全局配置文件
和Mybatis映射文件
,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。- mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
- 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
- SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
- Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括java的简单类型、HashMap集合对象、POJO对象类型。
MyBatis入门
创建Maven项目
- 略
添加依赖信息
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>x.x.xx</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>x.x.xx</version> </dependency> </dependencies>
加入配置文件
- 在resources目录中添加Mybatis的核心配置
mybatis-config.xml
、log4j日志文件log4j.properties
- 也可去官方文档中找到这些配置文件中的内容,日志文件可去【日志框架】文章中找
<?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> <!-- 和spring整合后 environments配置将废除 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis_01?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <!-- 添加映射文件位置 --> <mappers> <mapper resource="xxx/xx/mapper/XxxMapper.xml"/> </mappers> </configuration>
创建POJO
- domain、bean、entity、pojo
- 在不同的场合使用的对象的分类:
- po : Persistent Object (持久化对象)
- vo:View Object (视图对象 ,PageBean)
- dto: Data Transfer Object (数据传输对象 ,系统与系统之间传递数据)
- bo : Business Object (业务对象)
什么是POJO:
- POJO是Plain Old Java Objects的缩写,POJO实质上可以理解为
简单的实体类
,顾名思义POJO类的作用是方便程序员使用数据库中的数据表- 对于广大的程序员,可以很方便的将POJO类当做对象来进行使用,当然也是可以方便的调用其
get、set
方法。
加入sql映射文件
- 创建XxxMapper.xml文件
- 将XxxMapper.xml添加在mybatis-config.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"> <!-- namespace:命名空间,用于隔离sql --> <mapper namespace="test"> <!-- id:statement的id 或者叫做sql的id--> <!-- parameterType:声明输入参数的类型 --> <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 --> <!-- #{}:输入参数的占位符,相当于jdbc的? 如果是简单类型(基本类型、字符串类型)名称可以任意--> <!-- 如果传入的参数是简单数据类型,使用${}里面必须写value --> <select id="xxxx" parameterType="Integer" resultType="com.xxx.pojo.User"> SELECT * FROM `user` WHERE id = #{id} </select> </mapper>
连接程序
- MyBatis框架中涉及到的几个API:
- SqlSessionFactoryBuilder:
- 该对象负责根据MyBatis配置文件mybatis-config.xml构建SqlSessionFactory实例
- SqlSessionFactoryBuilder用于创建SqlSessionFactory,SqlSessionFactory一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。
- 所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
- SqlSessionFactory:
- 每一个MyBatis的应用程序都以一个
SqlSessionFactory对象
为核心。该对象负责创建SqlSession对象实例。- SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory
- SqlSession:
- 该对象包含了所有执行SQL操作的方法,用于执行已映射的SQL语句
- SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。
- 每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。
- 因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
- 打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。
- SqlSession的使用范围:
- SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
- SqlSession通过SqlSessionFactory创建。
- SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
- 代码:
// 1. 创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 2. 加载SqlMapConfig.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 3. 创建SqlSessionFactory对象 SqlSessionFactory factory = sqlSessionFactoryBuilder.build(inputStream); // 4.创建SqlSession SqlSession sqlSession = factory.openSession(); // 5.执行,要和映射文件中填写一致 User user = sqlSession.selectOne("test.xxxx", 1); // 6. 打印结果 System.out.println(user); //sqlSession.commit();添加、删除,修改需要提交 // 7. 释放资源 sqlSession.close();
selectOne和selectList
- 动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据XxxMapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
其他
#{}和${}的区别
- (1)#{}表示一个
占位符号
,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入
。 #{}可以接收简单类型值或pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或其它任意名称
。- (2)${}表示
拼接sql串
,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value
。
parameterType和resultType
- parameterType:指定
输入参数类型
,MyBatis通过ognl从输入对象中获取参数值拼接在sql中。- resultType:指定
输出结果类型
,MyBatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中
实现增删改
增
- 映射文件配置
<insert>
标签,用于执行插入操作。- 在插入操作完成之前或之后,可以配置
<selectKey>
标签获得生成的主键的值,获得插入之前还是之后的值,可以通过配置order属性来指定。
<insert id="addUser" parameterType="com.qf.po.User"> <!-- selectKey 标签实现主键返回,查询主键,在标签内需要输入查询主键的sql --> <!-- keyProperty:主键对应的pojo中的哪一个属性 --> <!-- order:指定查询主键的sql和insert语句的执行顺序,设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql --> <!-- resultType:设置返回的id的类型 --> <!-- LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的ID,它必须配合insert语句一起使用 注意:它是获取当前事务中,最近一次增加的主键值 --> <selectKey keyProperty="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO USER(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address}) </insert>
删
- 在映射文件文件中使用
<delete>
标签配置删除的statement。
<delete id="deleteUser" parameterType="int"> delete from user where id=#{id} </delete>
改
- 在映射文件使用
<update>
标签配置修改的statement。
<update id="updateUser" parameterType="com.qf.pojo.User"> update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id= #{id} </update>
MyBatis两种开发方式
- 使用MyBatis开发Dao,通常有两种方式,即原始Dao开发方式和Mapper接口动态代理开发方式。推荐使用第二种。
- MyBatis配置文件
- 封装MyBatisUtils工具类
- 原生Dao方式,编写
Dao层接口
和Dao层实现类
(老方式)- 另一种方式,Mapper接口动态代理方式(重要的,推荐的)
- 动态代理开发规范
- Mapper接口开发方法只需要程序员编写XxxMapper接口(相当于Dao接口)
- 由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同Dao层接口实现类方法。
- Mapper接口开发需要遵循以下规范:
- Mapper.xml文件中的namespace与mapper接口的类路径相同。
- Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
- Mapper接口方法的输入参数类型和Mapper.xml中定义的每个sql 的parameterType的类型相同(注意:Mapper.xml中parameterType可不写,如果不写则由Mapper接口中的方法参数类型决定)
- Mapper接口方法的返回值类型和Mapper.xml中定义的每个sql的resultType(输出参数类型)的类型相同
- XxxMapper.java接口(Xxx和实体类名相对应)
public interface XxxDao { Xxx queryXxxById(int id); List<Xxx> queryXxxByUsername(String username); void saveXxx(Xxx xxx); }
- XxxMapper.xml映射文件与XxxMapper.java接口相对应
<?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 --> <!-- 还有一个很重要的作用,使用动态代理开发DAO, 1. namespace必须和Mapper接口类路径一致 --> <mapper namespace="com.xxx.mapper.XxxMapper"> <!-- 根据用户id查询用户 --> <!-- 2. id必须和Mapper接口方法名一致 --> <!-- 3. parameterType必须和接口方法参数类型一致 --> <!-- 4. resultType必须和接口方法返回值类型一致 --> <select id="queryXxxById" parameterType="int" resultType="com.xxx.pojo.Xxx"> select * from xxx where id = #{id} </select> <!-- 根据用户名查询用户 --> <select id="queryXxxByUsername" parameterType="string" resultType="com.xxx.pojo.Xxx"> select * from xxx where username like '%${value}%' </select> <!-- 保存用户 --> <insert id="saveXxx" parameterType="com.xxx.pojo.Xxx"> <selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int"> select last_insert_id() </selectKey> insert into xxx(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address}); </insert> </mapper>
把java目录中配置也编译程序中:
- 需要在Maven项目的pom.xml文件中添加下面的代码,不然MaBatis配置文件找不到Mapper.xml文件路径。
<!--把java目录中配置也包含在项目的类路径中--> <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>