什么是Mybatis
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plan Old Java Objects,普通的 Java 对象)映射成数据库中的记录
Mybatis核心配置文件(mybatis-config.xml)
XML 配置文件包含对 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>
<!--应用配置文件-->
<properties resource="database.properties"></properties>
<!--环境池-->
<environments default="mysql">
<!--具体环境配置-->
<environment id="mysql">
<!--事务管理器-->
<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>
<!--
在核心配置文件中导入映射文件的路径 使映射文件生效
我们项目中要用的映射文件都要导入进来
-->
<mappers>
<mapper resource="mapper/PhoneMapper.xml"></mapper>
<mapper resource="mapper/BrandMapper.xml"></mapper>
</mappers>
</configuration>
使用核心配置文件链接数据库
try {
//1,读取mybatis的核心配置文件
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
//2,永mybatis创建工厂 =》 SqlSessionFactoryBuilder
SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(is);
//3、通过工厂生产一个具体的SqlSession
// jsp中的session是一个网页会话, SqlSession是数据库对话
SqlSession session= ssf.openSession();
//4.调用,利用反射得到接口对象(底层寻找到跟接口同名的xml映射文件来生产)
BananaMapper mapper = session.getMapper(BananaMapper.class);
} catch (IOException e) {
e.printStackTrace();
}
当我们将核心配置文件配置好以及链接对象都得到之后,就可以使用Mybatis来进行对数据库的操作了(当然使用Mybatis是需要导入jar包的可以去官网下载,下面是maven项目中导入Mybatis依赖)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
使用Mybatis执行sql语句
接下来就是我们要通过以前JDBC的三层,带入Mybatis中,将三层中的一些内容进行改造替换然后变成Mybatis项目
这是我们传统的三层可以看到是通过接口与实现类来实现的,所以我能使用Mybatis需要改动一下,当然三层不变
通过对比可以看出我们将dao层变成了mapper,其次我们也没有通过实现类来实现接口了,而是通过xml文件来映射,然后利用Java的反射机制来得到接口对象,在映射文件中通过特定标签来实现方法
接口内的方法
import entity.Work;
import java.util.List;
public interface WorkMapper {
/**
* 查询所有
* @return 所有记录
*/
List<Work> getAll();
/**
* 查询所有转正的员工
* @return 查询的数据
*/
List<Work> getFlag();
/**
* 查询今年入职的员工
* @return 查询的数据
*/
List<Work> getDate();
/**
* 按指定薪资查询工人
* @param money 工资
* @return 查询的数据
*/
List<Work> getMoney(double money);
/**
* 新增
* @param w 新增对象
* @return 影响行数
*/
int insert(Work w);
/**
* 删除
* @param id 数据编号
* @return 影响行数
*/
int delete(int id);
/**
* 修改
* @param w 修改对象
* @return 影响行数
*/
int update(Work w);
}
在xml映射文件中实现方法,编写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="dao.WorkMapper">
<select id="getAll" resultType="entity.Work">
select * from work
</select>
<select id="getFlag" resultType="entity.Work">
select * from work where flag=1
</select>
<select id="getDate" resultType="entity.Work">
select * from work where jdate between STR_TO_DATE(CONCAT(year(now()),'-01-01 ','00:00:00'),'%Y-%m-%d %H:%i:%s') and now()
</select>
<select id="getMoney" resultType="entity.Work">
select * from work where wmoney>#{money}
</select>
<insert id="insert" parameterType="entity.Work">
insert into work(wname,waddress,wage,wmoney,flag,wdate,jdate)
values(#{wname},#{waddress},#{wage},#{wmoney},#{flag},#{wdate},#{jdate})
</insert>
<delete id="delete" parameterType="int">
delete
from work
where wid=#{id};
</delete>
<update id="update" parameterType="entity.Work">
update work
set wname =#{wname},waddress =#{waddress},wage=#{wage},wmoney=#{wmoney},flag=#{flag},wdate=#{wdate},jdate=#{jdate}
where wid=#{wid};
</update>
</mapper>
在xml文件中有 insert ,delete ,update ,select 四个标签分别执行对数据库的增删改查语句,在增删改标签中有 parameterType 属性可设置传入参数的类型,查询寻语句中有 resultType 属性可设置返回数据的类型
说到resultType就需要说一下 resultMap,在我们通过xml来执行sql语句查询时往往会放回多条数据我们一般使用List集合放我们实体类对象去接收,在我们以前用的三层中是将每条数据遍历出来将对应的值通过实体类的set方法打包成一个对象,再将对象存入List中,Mybatis帮我们简化了这一步,但是我们需要将实体类中的属性名与表中的列名保持一致,但是有时候我们定义的属性名并不能保持一致,所以我们可以通过resultMap来手动建立映射规则。如下代码:
<!--手动建立映射规则-->
<resultMap id="BnaMap" type="entity.Banan">
<!--主键用id标签-->
<id property="bid" column="bid"></id>
<!--其他用result 标签-->
<result property="bname" column="bname"></result>
<result property="bprice" column="bprice"></result>
<result property="bcolor" column="bcolor"></result>
<association property="bp" javaType="entity.Place">
<id property="pid" column="pid"></id>
<result property="pname" column="pname"></result>
</association>
<association property="bt" javaType="entity.BanType">
<id property="tid" column="tid"></id>
<result property="tname" column="tname"></result>
</association>
</resultMap>
当然手动建立了映射规则后,我们在查询时要使用此规则需要使用时通过我们 selelct 标签中的 resultMap属性来调用 让其的值等于 自定义映射关系的id
Mybatis动态sql语句
当我们在进行修改,条件查询操作时可能会碰到一些不需要修改或者空值的条件,这时候我们以前的方法就是通过写if判断来处理,这样代码繁琐我们编写吃力而且容易出现异常,Mybatis为我们提供了动态sql语句,可以直接在编写sql语句时通过一些标签来完成这些功能,常用的有 if , foreach , where , set等等
具体使用如下:
<!--
查询行数
-->
<select id="queryCount" resultType="int">
select count(*)
from phone
<where>
<if test="price!=null">
price=#{price}
</if>
<if test="color!=null">
and pcolor=#{color}
</if>
<if test="bid!=0 and bid!=null">
and bid=#{bid}
</if>
</where>
</select>
<!--分页查询-->
<select id="queryByTLimit" resultMap="map">
select *
from phone join brand b on phone.bid = b.bid
<if test="price!=null">
and price>#{price}
</if>
<if test="color!=null">
and pcolor=#{color}
</if>
<if test="bid!=0 and bid!=null">
and phone.bid=#{bid}
</if>
limit #{index},#{size}
</select>
<!--通过主键修改数据-->
<update id="update" parameterType="entity.Phone">
update phone
<set>
<if test="pname != null and pname != ''">
pname = #{pname},
</if>
<if test="pcolor != null and pcolor != ''">
pcolor = #{pcolor},
</if>
<if test="price != null">
price = #{price},
</if>
<if test="b.bid != null">
bid = #{b.bid},
</if>
</set>
where pid = #{pid}
</update>
在我认为最好的就是帮我们解决了sql语句的拼接的问题
Mybatis的自动装配
当我们在多表联查时,我们必不可少的就是使用resultMap自定义映射关系 在我们的实体类中主表的实体类会包含副表的实体类对象 , 自定义映射关系时我们需要将实体类的属性和表的列对应 , 如果有两个或者三个表时可能代码会稍微有些多但也许还能接收,但是如果一旦有更多表的时候这将是一个极其复杂的事情,而且容易出错,所以Mybatis为我们提供了自动装配,我们需要做的就是在核心配置文件中添加标签,如下:
<settings>
<!--全映射 标签-->
<setting name="autoMappingBehavior" value="FULL"/>
</settings>
且必须添加在指定位置否则核心配置文件会报错,然后我们就只需要在映射文件中的resultMap标签编写关联对象即可,如下
缓存
Mybatis中分为一级缓存和二级缓存
一级缓存只存在于Sqlsession对象之中,当我们执行查询方法时只要我们没有执行close()方法释放Sqlsession和在中间执行增删改的方法一级缓存就一直都在 参考下面代码:
执行结果如下:
可以看到我们调用两次方法只执行了一次sql语句,如果我们在第一次调用和第二次调用之间执行增删改操作或者释放Sqlsession对象就会清楚第一调用的缓存
二级缓存当我们多个Sqlsession对象访问同一数据我们页不可能每次都去访问数据库,这样会给数据库带来巨大压力,所以我们需要开启二级缓存.方式就是在核心配置文件以及映射文件中都需要编写标签,我们的实体类都需要实现Serializable接口实现序列化,并且每个Sqlsession执行完之后必须释放(不然会进入一级缓存) 配置文件如下:
用注解实现mybatis
当我们在进行一些简单的增删改查的功能时去xml映射文件中的话就会稍显复杂所以我们可以用注解的方式实现简单的增删改查对应注解为( @insert(sql) @Delete(sql) @Update(sql) @Select(sql))
如下代码:
/**
* 查询所有
* @return
*/
@Select("select * from phone")
List<Phone> getAll();
/**
* 删除指定
* @param id 编号
* @return 影响行数
*/
@Delete("delete from phone where pid = #{id}")
int deleteById(int id);
结尾福利:
我们每次使用Mybatis时都需要现获得Sqlsession对象,如果每次都要写相同的代码就太繁琐了,所以我们可以写一个Mybatis的工具类就好了,每次调用工具类中的方法即可,我就分享在下面了,写的不好请勿见怪:
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.InputStream;
public class MyBatisUtil {
//获得SqlSession工厂
private static SqlSessionFactory factory;
//创建ThreadLocal绑定当前线程中的SqlSession对象
private static final ThreadLocal<SqlSession> THREAD_LOCAL = new ThreadLocal<SqlSession>();
static {
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (Exception e) {
e.printStackTrace();
}
}
//获得连接(从THREAD_LOCAL中获得当前线程SqlSession)
private static SqlSession openSession(){
SqlSession session = THREAD_LOCAL.get();
if(session == null){
session = factory.openSession();
THREAD_LOCAL.set(session);
}
return session;
}
/**
* 释放连接(释放当前线程中的SqlSession)
*/
public static void closeSession(){
SqlSession session = THREAD_LOCAL.get();
session.close();
THREAD_LOCAL.remove();
}
/**
* 提交事务(提交当前线程中的SqlSession所管理的事务)
*/
public static void commit(){
SqlSession session = openSession();
session.commit();
closeSession();
}
/**
* 回滚事务(回滚当前线程中的SqlSession所管理的事务)
*/
public static void rollback(){
SqlSession session = openSession();
session.rollback();
closeSession();
}
/**
* 获得接口实现类对象
* @param clazz 泛型对象
* @param <T> 泛型
* @return
*/
public static <T> T getMapper(Class<T> clazz){
SqlSession session = openSession();
return session.getMapper(clazz);
}
}
谢谢阅读 ! ! `!