麒麟Java工程师 潜水
  • 2发帖数
  • 1主题数
  • 0关注数
  • 0粉丝
开启左侧

掌握7个小技巧,轻松玩转Mybatis数据库

[复制链接]
麒麟Java工程师 发表于 2021-8-12 20:02:58 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
媒介

利用Mybatis实行数据库操作,起首要获取SqlSession,通过它进一步获取Mapper接口代理对象,最后通过代理对象发起数据库操作

                               
登录/注册后可看大图

这是利用Mybatis举行数据库操作的一个Demo,通过构建DataSource、TransactionFactory、Environment、Configuration并将它们组装在一起得到SqlSessionFactory,此后就可以通过它获取SqlSession
sqlSessionFactory.openSession();通过会话工厂开启一个会话

@Testpublic void readerTest() throws IOException {    PageUtil.setPagingParam(1,11);    //得到一个Reader处理类(字符流)    try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/mytest/mybatis-config.xml")) {        // environment:数据源ID 在mybatis-config.xml  标签内里设置的 id 为development的数据源信息(非必传)        // properties :设置文件信息。一般是数据库设置信息。可以在这里举行设置 也可以在mybatis-config.xml 通过 标签举行引入properties设置文件        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,"development", Resources.getResourceAsProperties("org/apache/ibatis/mytest/db.properties"));    }    SqlSession sqlSession = sqlSessionFactory.openSession();    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);    mapper.insertStudent(new StudentDto(11, "12", 24, Arrays.asList(1, 2, 3, 4, 5)));    sqlSession.commit();    List rs = mapper.getStudentsByAlias();    System.out.println(rs.toString());}复制代码看下openSession内里是怎么实现的

1.得到设置的情况数据源信息
2.根据数据源信息得到一个事件工厂
3.新建一个事件
4.根据事件得到实行器(代表一个事件对应一个实行器)
5.创建默认的SqlSession对象
/** * 打开一个session 来自 数据源 * * @param execType   实行器类型       默认ExecutorType是 ExecutorType.SIMPLE * @param level      事件隔离级别 * @param autoCommit 是否自动提交事件 * * @return SqlSession会话对象 */private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {    /*        之前sqlSessionFactoryBuilder.build(InputStream inputStream)          ===》 xMLConfigBuilder.parse()  ====》 将设置文件中的数据源和sql语句封装赋值给了Configuration对象        所以,这边可以直接获取对象中的相干信息     */    Transaction tx = null;    try {        // 获取情况设置        final Environment environment = configuration.getEnvironment();        // 事件工厂        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);        // 新建一个事件        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);        // 拿到实行器Executor        final Executor executor = configuration.newExecutor(tx, execType);        // 创建默认的SqlSession对象        return new DefaultSqlSession(configuration, executor, autoCommit);    } catch (Exception e) {        closeTransaction(tx); // may have fetched a connection so lets call close()        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);    } finally {        ErrorContext.instance().reset();    }}复制代码看下实行器的创建过程

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {    executorType = executorType == null ? defaultExecutorType : executorType;    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;    Executor executor;    if (ExecutorType.BATCH == executorType) {        // 批处理实行器        executor = new BatchExecutor(this, transaction);    } else if (ExecutorType.REUSE == executorType) {        // 复用实行器        executor = new ReuseExecutor(this, transaction);    } else {        // 默认实行器        executor = new SimpleExecutor(this, transaction);    }    /*            1、一级缓存默认是开启的            2、二级缓存默认是关闭的            3、先实行一级缓存还是二级缓存,先实行二级缓存     */    // cacheEnabled一级缓存默认是开启的,为true的话代表开启二级缓存    // 二级缓存通过装饰器模式的方式加载进实行器中    if (cacheEnabled) {        executor = new CachingExecutor(executor);    }    // 重点:插件拦截器过滤链 把实行器怼到内里去    executor = (Executor) interceptorChain.pluginAll(executor);    return executor;}复制代码看下插件的植入过程

mybatis会遍历所有设置的插件来举行代理。多个插件会重复代理
/** * 简化动态代理创建的方法 * * @param target * @param interceptor * * @return */public static Object wrap(Object target, Interceptor interceptor) {    // 获取自界说插件中,通过@Intercepts注解指定的方法    Map type = target.getClass();    // 根据类型获取所有拦截的接口    Class[] interfaces = getAllInterfaces(type, signatureMap);    if (interfaces.length > 0) {        // 假如必要拦截,则用JDK动态代理生成一个代理对象        return Proxy.newProxyInstance(                type.getClassLoader(),                interfaces,                new Plugin(target, interceptor, signatureMap));    }    return target;}复制代码看下Plugin

Plugin有三个参数
target:目的对象Executor、ParameterHandler、ResultSetHandler、StatementHandler实例 或者另一个插件代理对象。
interceptor:对应插件类加载对象
signatureMap:插件注解生效的方法
package org.apache.ibatis.plugin;import org.apache.ibatis.reflection.ExceptionUtil;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;/** * @author Clinton Begin */public class Plugin implements InvocationHandler {    /** 目的对象Executor、ParameterHandler、ResultSetHandler、StatementHandler实例 或者另一个插件代理对象*/  /**多个插件的加载采用在target内里传入代理对象实现的*/    private final Object target;    /** 用户自界说拦截器实例 */    private final Interceptor interceptor;    /** Intercepts注解指定的方法 */    private final Map, Set> signatureMap = getSignatureMap(interceptor);        // 获取目的对象的类型        Class type = target.getClass();        // 根据类型获取所有拦截的接口        Class[] interfaces = getAllInterfaces(type, signatureMap);        if (interfaces.length > 0) {            // 假如必要拦截,则用JDK动态代理生成一个代理对象            return Proxy.newProxyInstance(                    type.getClassLoader(),                    interfaces,                    new Plugin(target, interceptor, signatureMap));        }        return target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        try {            Set methods = signatureMap.get(method.getDeclaringClass());            // 假如是@Intercepts注解指定的方法,就调用拦截的逻辑            if (methods != null && methods.contains(method)) {                // 将目的方法信息封装成Invocation给拦截器的intercept()方法利用                return interceptor.intercept(new Invocation(target, method, args));            }            return method.invoke(target, args);        } catch (Exception e) {            throw ExceptionUtil.unwrapThrowable(e);        }    }    private static Map, Set> signatureMap = new HashMap();        for (Signature sig : sigs) {            // 把所有@Signature指定拦截的组件、方法添加到map中去            Set methods = signatureMa.computeIfAbsent(sig.type(), k -> new HashSet());            try {                Method method = sig.type().getMethod(sig.method(), sig.args());                methods.add(method);            } catch (NoSuchMethodException e) {                throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);            }        }        return signatureMap;    }    private static Class[] getAllInterfaces(Class type, Map c : type.getInterfaces()) {                if (signatureMap.containsKey(c)) {                    interfaces.add(c);                }            }            type = type.getSuperclass();        }        return interfaces.toArray(new Class[0]);    }}复制代码可以看出,创建sqlsession颠末了以下几个紧张步骤:

  • 从设置中获取Environment;
  • 从Environment中取得DataSource;
  • 从Environment中取得TransactionFactory;
  • 从DataSource里获取数据库连接对象Connection;
  • 在取得的数据库连接上创建事件对象Transaction;
  • 创建Executor对象(该对象非常紧张,究竟上sqlsession的所有操作都是通过它完成的);
  • 创建sqlsession对象。
原文链接:https://juejin.cn/post/6995479326900617223
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

猜你喜欢
在线客服邮箱
wxcy#wkgb.net

邮箱地址#换为@

Powered by 创意电子 ©2018-现在 专注资源实战分享源码下载站联盟商城