一文搞懂mybatis Executor执行器体系

 众所周知mybatis是目前主流的持久层框架,使用广泛。先来看下mybatis执行流程

 

 

接下来我们再复习下JDBC连接

 

 代码演示

 1    private  Properties prop = new Properties();;
 2 
 3    private Connection connection;
 4
 5 
 6     // 获取数据库连接
 7     @Before
 8     public void init() throws SQLException, IOException {
 9         prop.load(this.getClass().getResourceAsStream("/app.properties"));
10         String URL =  String.valueOf(prop.get("jdbc.url"));
11         String USERNAME = String.valueOf(prop.get("jdbc.username"));;
12         String PASSWORD = String.valueOf(prop.get("jdbc.password"));;
13         connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
14     }
15 
16     @Test
17     public void jdbcTest() throws SQLException {
18         String sql = "SELECT * FROM user ";
19         // 解析sql
20         PreparedStatement sql1 = connection.prepareStatement(sql);
21         // 执行sql语句
22         sql1.execute();
23         // 获取执行结果
24         ResultSet resultSet = sql1.getResultSet();
25         while (resultSet.next()) {
26             System.out.println(resultSet.getString(2));
27         }
28         resultSet.close();
29         // 关闭连接
30         sql1.close();
31     }

 

接下来着重介绍下下Executor执行器体系

 

 

Executor类图

 

Executor是MyBatis的SQL顶层执行器接口,声明了对数据库所有的增删改查操作。其中 query()和queryCursor()方法用于执行查询操作,update()方法用于执行插入、删除、修改操作。

BaseExecutor是Executor的抽象实现类,采用模板设计模式,它声明的抽象方法由子类SimpleExecutor、ReuseExecutor、BatchExecutor实现。

 1   protected abstract int doUpdate(MappedStatement ms, Object parameter)
 2       throws SQLException;
 3 
 4   protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
 5       throws SQLException;
 6 
 7   protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
 8       throws SQLException;
 9 
10   protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
11       throws SQLException;

 

SimpleExecutor是基础的Executor,能够完成基本的增删改查操作

 

 1     private static Configuration configuration;
 2     private static Transaction jdbcTransaction;
 3     private static MappedStatement ms;
 4     private static SqlSessionFactory factory;
 5 
 6     @Before
 7     public void init() throws IOException {
 8         // 获取构建器
 9         SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
10         // 解析XML 并构造会话工厂
11         factory = factoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
12         configuration = factory.getConfiguration();
13         jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());
14         // 获取SQL映射
15         ms = configuration.getMappedStatement("org.coderead.mybatis.UserMapper.selectByid");
16     }
17 
18     // 简单执行器测试
19     @Test
20     public void simpleTest() throws SQLException {
21         SimpleExecutor executor = new SimpleExecutor(configuration, jdbcTransaction);
22         List<Object> list = executor.doQuery(ms, 10, RowBounds.DEFAULT,
23                 SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(10));
24 
25         executor.doQuery(ms, 10, RowBounds.DEFAULT,
26                 SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(10));
27         System.out.println(list.get(0));
28     }

 

ResueExecutor对JDBC中的Statement对象做了缓存,当执行相同的SQL语句时,直接从缓存中取出Statement对象进行复用,避免了频繁创建和销毁Statement对象,从而提升系统性能,这是享元思想的应用。

 

 1     private static Configuration configuration;
 2     private static Transaction jdbcTransaction;
 3     private static MappedStatement ms;
 4     private static SqlSessionFactory factory;
 5 
 6     @Before
 7     public void init() throws IOException {
 8         // 获取构建器
 9         SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
10         // 解析XML 并构造会话工厂
11         factory = factoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
12         configuration = factory.getConfiguration();
13         jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());
14         // 获取SQL映射
15         ms = configuration.getMappedStatement("org.coderead.mybatis.UserMapper.selectByid");
16     }
17    // 重用执行器
18     @Test
19     public void ReuseTest() throws SQLException {
20         ReuseExecutor executor = new ReuseExecutor(configuration, jdbcTransaction);
21         List<Object> list = executor.doQuery(ms, 10, RowBounds.DEFAULT,
22                 SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(10));
23         //  相同的SQL 会缓存对应的 PrepareStatement-->缓存周期:会话
24         executor.doQuery(ms, 10, RowBounds.DEFAULT,
25                 SimpleExecutor.NO_RESULT_HANDLER, ms.getBoundSql(10));
26         System.out.println(list.get(0));
27     }

 

BatchExecutor则会对调用同一个Mapper执行的update、insert和delete操作,调用Statement对象的批量操作功能。

 1     private static Configuration configuration;
 2     private static Transaction jdbcTransaction;
 3     private static MappedStatement ms;
 4     private static SqlSessionFactory factory;
 5 
 6     @Before
 7     public void init() throws IOException {
 8         // 获取构建器
 9         SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
10         // 解析XML 并构造会话工厂
11         factory = factoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
12         configuration = factory.getConfiguration();
13         jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());
14         // 获取SQL映射
15         ms = configuration.getMappedStatement("org.coderead.mybatis.UserMapper.selectByid");
16     }
17  // 批处理执行器
18     @Test
19     public void BatchTest() throws SQLException {
20         BatchExecutor executor = new BatchExecutor(configuration, jdbcTransaction);
21         MappedStatement setName = configuration
22                 .getMappedStatement("org.coderead.mybatis.UserMapper.setName");
23         Map param = new HashMap<>();
24         param.put("arg0", 10);
25         param.put("arg1", "鲁班大叔 is good man");
26         executor.doUpdate(setName, param); //设置
27         executor.doUpdate(setName, param);// 设置
28         executor.doFlushStatements(false);
29     }

 

 

 

 

另外,我们知道MyBatis支持一级缓存和二级缓存,当MyBatis开启了二级缓存功能时,会使用CachingExecutor对SimpleExecutor、ResueExecutor、BatchExecutor进行装饰,为查询操作增加二级缓存功能,这是装饰器模式的应用。

 

 1     private static Configuration configuration;
 2     private static Transaction jdbcTransaction;
 3     private static MappedStatement ms;
 4     private static SqlSessionFactory factory;
 5 
 6     @Before
 7     public void init() throws IOException {
 8         // 获取构建器
 9         SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
10         // 解析XML 并构造会话工厂
11         factory = factoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
12         configuration = factory.getConfiguration();
13         jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());
14         // 获取SQL映射
15         ms = configuration.getMappedStatement("org.coderead.mybatis.UserMapper.selectByid");
16     }
17     @Test
18     public void cacheExecutorTest() throws SQLException {
19         // BaseExecutor
20         Executor executor = new SimpleExecutor(configuration, jdbcTransaction);
21         // 装饰器模式
22         Executor cachingExecutor = new CachingExecutor(executor);// 二级缓存相关逻辑 执行数据操作逻辑
23 
24         cachingExecutor.query(ms, 10, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
25         cachingExecutor.commit(true);
26         //  提交之后才会更新
27         cachingExecutor.query(ms, 10, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
28 
29     }

 

posted @ 2020-06-03 20:03  Mr_差不多  阅读(668)  评论(0)    收藏  举报