MyBatis
前言
本文章仅仅记录阐述MyBatis的基本使用和注解式使用,不涉与任何其他框架的整合,使用的MyBatis版本为 3.5.6 。
基本使用
1.导入jar包
使用MyBatis 首先需要在项目中导入两个最基本的jar包。mybatis-3.5.6
和驱动包mysql-connector-java-8.0.21
(请根据自己的需求导入合适的版本)
2.创建MyBatis配置文件
MyBatis配置文件是MyBatis框架的核心,也是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>
<!--指定数据库属性配置文件的位置-->
<properties resource="resources/jdbc"/>
<!-- environments 为数据库配置信息 该元素中的 default 指定当前默认使用的数据库配置-->
<environments default="development"><!--default指定要使用 environments 中的那套数据路配置-->
<!--每一个environment元素都为一个数据库连接的配置,若要使用多个数据库请配置多个 environment 元素-->
<environment id="development"><!--id属性指定了此套数据库配置的名称-->
<transactionManager type="JDBC"/><!--transactionManager 指定了事务管理器-->
<dataSource type="POOLED"><!--dataSource数据源,此处可以指定数据库连接池,POOLED为Mybatis自带连接池-->
<!--在properties属性文件中指定数据库的信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--指定mapper文件的位置-->
<mappers>
<mapper resource="Mapper/*mapper.xml"/>
</mappers>
</configuration>
3.创建实体类
实体类服务于Mapper映射文件和Mapper接口中的返回值与形式参数列表。
若为返回值则实体类中的属性至少应包含sql语句中返回的字段,返回值常用于select语句。
若为形式参数列表,则至少包含sql语句中需要使用的属性。
4.创建Mapper映射文件
mybatis的官方帮助文档中提供了sql映射文件的模板,根据业务实际情况填写其中元素的值。Mapper映射文件是书写sql语句的地方,基本每一张表对应一个Mapper映射文件,Mapper映射文件的文件名需和Mapper接口文件名一致,且在同一包内(默认为在同包内检索,其他包请在Mybatis配置文件中指定)。
<?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="此值指向了Mapper接口的路径名">
<!--sql语句......-->
</mapper>
5.书写SQL语句
在Mybatis中使用SQL标签书写SQL语句,SQL标签包含了四种SQL标签:select
delete
update
insert
。标签内由SQL语句和属性组成。部分属性虽然可以在SQL元素中声明但是可能会发生异常,或者无效。
5.0 SQL元素的属性
|
5.1 select语句
在Mapper中使用select元素声明SQL语句。
以下为sql语句的结构:
<select id="此处指定的id必须与Mapper接口中的方法同名" resultType="本次查询的结果必须与Mapper接口中的返回值相同" parameterType="本次查询需要的参数">
select * from user
</select>
5.2 delete语句
在Mapper中使用delete元素声明SQL语句。
以下为sql语句的结构:
<delete id="此处指定的id必须与Mapper接口中的方法同名" parameterType="本次删除需要的参数" >
delete from user where name = admin
</delete>
5.3 update语句
在Mapper中使用update元素声明SQL语句。
以下为sql语句的结构:
<update id="此处指定的id必须与Mapper接口中的方法同名" parameterType="本次更新需要的参数">
update user set name = admin ,age = 15 where id = 001
</update>
5.4 insert语句
在Mapper中使用insert元素声明SQL语句。
以下为sql语句的结构:
<insert id="此处指定的id必须与Mapper接口中的方法同名" parameterType="本次插入 需要的参数">
insert into user (id,name,age)values (001,admin,15)
</insert>
6.创建Mapper接口
创建Mapper接口,mybatis使用接口式声明执行sql语句的方法,接口名必须和Mapper文件名一致且大小写相同,接口中的方法的属性必须和Mpper文件中的sql元素一一对应,(方法名相同,返回值相同,形式参数列表相同)
7.创建Service类
我们通常创建一个 Service 包将业务代码统存放,在业务层调用Mapper接口来执行SQL语句,而不是写在一起使功能界线模糊,使各层代码高耦合难以阅读和区分。
8. 创建SqlSession管理类
我们通常在WEB项目中的控制器类调用Service包中的业务类,再使用业务类调用Mapper接口中的方法完成SQL语句的执行
构造SqlSession
package session;
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.InputStream;
public class SessionManager {
private static final SqlSessionFactory sqlSessionFactory;
/*在线程中存储SqlSession*/
public static final ThreadLocal<SqlSession> sqlSessionThreadLocal = new ThreadLocal<>();
static{
String configPath = "MyBatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(configPath);
} catch (IOException e) {
e.printStackTrace();
}
/*读取配置文件生成Config*/
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
public static SqlSession getSession(){
SqlSession session = sqlSessionThreadLocal.get();
if (session == null){
/*MyBatis默认是手动提交事务事务的,使用此方法的重载sqlSessionFactory.openSession(true);将事务定为自动提交*/
session = sqlSessionFactory.openSession();
sqlSessionThreadLocal.set(session);
}
return session;
}
public static void colesSession(SqlSession session){
if (session != null ){
session.close();
sqlSessionThreadLocal.remove();
}
}
}
9.处理事务
使用JDK动态代理处理事务
示例:
package affairs;
import org.apache.ibatis.session.SqlSession;
import session.SessionManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyAffairs implements InvocationHandler {
private final Object object;
public ProxyAffairs(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
SqlSession session = null;
try{
SessionManager.getSession();
obj = method.invoke(object,args);
session.commit();
}catch (RuntimeException e){
session.rollback();
e.printStackTrace();
}finally {
SessionManager.colesSession(session);
}
return obj ;
}
public Object createProxy(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
}
}
封装
因为在使用sql语句时总是要进行事务处理,所以为了避免重复的代码我们应该将调用动态代理的方法封装起来,只用针对此方法调用,使得代码整洁。
public class SpecifyAffairsObject {
public static Object specifObject ( Object o){
return new ProxyAffairs(o).createProxy();
}
}
10.测试
import affairs.ProxyAffairs;
import affairs.SpecifyAffairsObject;
import domain.User;
import service.UserService;
import service.UserServiceImpl;
import session.SessionManager;
import mapper.UserMapper;
import java.util.List;
public class Test {
public static void main(String[] args) {
UserService service = (UserService)SpecifyAffairsObject.specifObject(new UserServiceImpl());
List<User> users = service.selectUser("张三");
for (User user:users) {
System.out.println(user);
}
}
}