为什么需要mybatis?
使用一个jdbc的数据库查询操作为例,每次进行一次查询操作都需要重新创建数据库连接,编写sql,执行sql,处理结果集,释放资源,在这个过程中有很多重复的操作,而且sql语句时硬编码,每次修改都得重新编译代码,基于这样的问题,有人设计了mybatis框架,主要用来解决以下问题:
- 使用数据库连接池管理数据库连接
- 将sql语句交给配置文件管理,通过读取配置文件来获取需要执行的sql语句,此时我们很容易想到,这样做带来了一些新的问题,而mybatis就会用一些方法来解决这样的问题,比如如何将sql语句和对应的方法绑定
- 传统的jdbc编程,处理结果集麻烦,此时mybatis则统一对结果集进行封装成Java对象,此时需要处理的就是将数据库的数据项和java对象进行映射
- 改变重复的异常处理机制,改为使用代理模式,使用一套逻辑代码处理所有的sql语句的执行
- 等等
mybatis如何处理这些问题?
使用一个mybatis的例子说明,首先使用mybatis需要创建一个mybatis的全局配置文件,这里叫mybatis-configuration.xml,引入mybatis配置文件的约束,这些约束就定义了mybatis配置文件的写法,然后mybatis框架就会按照这个约束的格式去处理获取所需要的信息而进行初始化。
- mybaits-configuration.xml比较重要的一个配置就是数据源的配置,也可以使用数据库连接池,但这样做的核心目的都是保证mybatis使用的都是这里配置的数据库连接信息。
- 同时核心配置文件会告诉mybatis去哪儿去查找映射配置文件等信息
<?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标签,当mybatis和spring整合之后,这个标签是不用配置的 -->
<!-- 可以配置多个运行环境,但是每个 SqlSessionFactory 实例只能选择一个运行环境
一、development:开发模式
二、work:工作模式-->
<environments default="development">
<!--id属性必须和上面的default一样 -->
<environment id="development">
<!--事务管理器
一、JDBC:这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围
二、MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期
比如 spring 或 JEE 应用服务器的上下文,默认情况下,它会关闭连接。然而一些容器并不希望这样,
因此如果你需要从连接中停止它,就可以将 closeConnection 属性设置为 false,比如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
-->
<transactionManager type="JDBC"/>
<!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdemo"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
- 编写需要操作的实体类的映射文件比如UserMapper.xml
此配置文件需要配置的是,关于User这个实体类的所有数据库查询,删除,更新所有操作的sql语句,在这里主要配置的就是一个映射关系,将sql语句同查询方法进行映射,将查询结果同实体类映射,将查询参数同sql语句里面的占位符进行映射,解决好这几个问题就能成功的使用mybatis进行一个完整而高效的sql查询了。
<?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="com.ys.po.userMapper">
<!-- 根据 id 查询 user 表中的数据
id:唯一标识符,此文件中的id值不能重复
resultType:返回值类型,一条数据库记录也就对应实体类的一个对象
parameterType:参数类型,也就是查询条件的类型
-->
<select id="selectUserById"
resultType="com.ys.po.User" parameterType="int">
<!-- 这里和普通的sql 查询语句差不多,对于只有一个参数,后面的 #{id}表示占位符,里面不一定要写id,写啥都可以,但是不要空着,如果有多个参数则必须写pojo类里面的属性 -->
select * from user where id = #{id}
</select>
<!-- 查询 user 表的所有数据
注意:因为是查询所有数据,所以返回的应该是一个集合,这个集合里面每个元素都是User类型
-->
<select id="selectUserAll" resultType="com.ys.po.User">
select * from user
</select>
<!-- 模糊查询:根据 user 表的username字段
下面两种写法都可以,但是要注意
1、${value}里面必须要写value,不然会报错
2、${}表示拼接 sql 字符串,将接收到的参数不加任何修饰拼接在sql语句中
3、使用${}会造成 sql 注入
-->
<select id="selectLikeUserName" resultType="com.ys.po.User" parameterType="String">
select * from user where username like '%${value}%'
<!-- select * from user where username like #{username} -->
</select>
<!-- 向 user 表插入一条数据 -->
<insert id="insertUser" parameterType="com.ys.po.User">
insert into user(id,username,sex,birthday,address)
value(#{id},#{username},#{sex},#{birthday},#{address})
</insert>
<!-- 根据 id 更新 user 表的数据 -->
<update id="updateUserById" parameterType="com.ys.po.User">
update user set username=#{username} where id=#{id}
</update>
<!-- 根据 id 删除 user 表的数据 -->
<delete id="deleteUserById" parameterType="int">
delete from user where id=#{id}
</delete>
</mapper>
使用注解的方法完成mybatis的实例
使用注解的方法完成mybatis的实例主要需要完成的内容也是和基于配置文件的方式类似,需要将对应的信息映射信息进行配置,将sql同类方法映射,将查询结果同java实体类映射,我们将映射关系写好之后,mybatis就会将查询结果给自动封装成实体类对象。主要解决的还是这些问题。
package com.ys.annocation;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.ys.po.User;
public interface UserMapper {
//根据 id 查询 user 表数据
@Select("select * from user where id = #{id}")
public User selectUserById(int id) throws Exception;
//向 user 表插入一条数据
@Insert("insert into user(username,sex,birthday,address) value(#{username},#{sex},#{birthday},#{address})")
public void insertUser(User user) throws Exception;
//根据 id 修改 user 表数据
@Update("update user set username=#{username},sex=#{sex} where id=#{id}")
public void updateUserById(User user) throws Exception;
//根据 id 删除 user 表数据
@Delete("delete from user where id=#{id}")
public void deleteUserById(int id) throws Exception;
}
mybatis核心配置文件的更多配置项
在mybatis-configuration.xml中加载db.properties文件并读取,此配置可以加载外部配置数据,然后将其数据写入mybatis的核心配置中。可以设置配置java类的别名,从而不需要配置完整的类路径映射。懒加载配置,在需要数据时进行数据加载。mybatis的逆向工程,通过配置xml文件,然后运行逆向工程代码即可。
mybatis的映射配置文件mapper.xml
使用条件标签配置动态sql,使用association标签配置完成一对多查询,联合查询。
mybatis和spring的整合
要完成mybatis和spring的整合,需要在spring的配置文件中配置sqlsessionFactory,然后使用工厂对象创建sqlsession对象,此时就可以获取mapper接口的代理对象,从而完成数据库查询操作。
参考文章mybatis详解系列来自博客园
通过自定义mybatis案例了解mybatis框架的执行逻辑
通过分析mybatis的主要运行类,理解mybatis的联调机制。
上述设计自定义mybatis框架的方式使用的设计模式是不规范的,但是mybatis的实现过程确实是按照下述的设计模式进行设计的。
- 通过resources类读取mybatis的核心配置文件,并获取配置项保存在 inputstream对象中。
- sqlsessionFactoryBuilder 对象可以通过 inputstream对象里面的配置信息,来生产一个工厂对象sqlsessionFactory,通过构建者模式构建的工厂对象具有很多组成部分,这些组成部分就是类,也代表着各种不同的配置信息
- 通过工厂对象产生sqlsession对象,sqlsession对象里面包含了数据库的连接信息。配置文件里面的信息等。
- 然后通过sqlsession对象获取接口的代理对象,通过代理模式完成数据库的通用查询方法,然后释放资源,进行结果封装,获取代理对象时sqlsession将接口的配置文件也同样传递过去,从而代理对象能按照配置文件进行结果封装。
理解mybatis框架使用的几大设计模式,先不讨论实现方法,讨论为什么使用这样的模式,以及这几种模式的应用场景
- 构建者模式
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。可以根据不同的简单对象来组成不同的复杂对象。
意图:将一个复杂对象的与其表示相分离,使得同样的构建过程可以创建不同的表示,就如同建房子一样,同样的施工队,同样的施工方法使用不同的材料(数据,或者对象)构建出不一样的房子,构造出来的对象一般都是复杂对象,而且这样的对象一般不直接采用new的方式进行创建。 - 工厂模式
工厂模式可以让创建类更加灵活,根据需要调用工厂不同的方法获取不同的对象。增添代码的灵活性。 - 代理模式
代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。