dw整合mybatis-plus

一 背景介绍

     本文主要是将dw-框架引入mybatis-plus。

二 依赖引入

     这里采用Druid数据库连接池(可更换)

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.3.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.8</version>
</dependency>

三 mybatisBundle的加载

        主要通过下面三个类来完成加载:

(1)MapperFactory主要负责Mapper文件的生成并注入HK2容器

(2)MybatisBundle负责与DW交互,让DW启动的时候加载MapperFactory

(3)SqlSessionTemplate主要是SqlSession的代理

详细介绍:

3.1  DW如何加载mybatis

    DW自身有一个扩展点,可以通过实现ConfiguredBundle接口

public class AppInit implements IOCApplicationInitialization {
    private static final Logger LOG = LoggerFactory.getLogger(AppInit.class);

    @Override
    public <T extends Configuration> void initialize(Bootstrap<T> bootstrap) {
        List<Class<?>> entities = EntityScanner.doScan();
        Objects.requireNonNull(entities, "Entity cant be null");
        LOG.info("Urm contains entity domain total:{}", entities.size());
        HibernateBundle<Configuration> hibernateBundle = new HibernateBundle<Configuration>(
                ImmutableList.<Class<?>>builder().add(entities.toArray(new Class<?>[0])).build(),
                new SessionFactoryFactory()) {
            @Override
            public PooledDataSourceFactory getDataSourceFactory(Configuration configuration) {
                DataSourceConfig config = (DataSourceConfig) configuration;
                return config.getDataSourceFactory("umebn_inventory_basic");
            }
        };
        MybatisBundle<Configuration> mybatisBundle = new MybatisBundle<Configuration>() {
            @Override
            public DataSourceFactory getDataSourceFactory(Configuration configuration) {
                DataSourceConfig config = (DataSourceConfig) configuration;
                return config.getDataSourceFactory("umebn_inventory_basic");
            }
        };
        HibernateHelper.setHibernateBundle(hibernateBundle);
        bootstrap.addBundle(hibernateBundle);
        bootstrap.addBundle(mybatisBundle);
    }
}

3.2 MybtaisBundle实现

这里在run方法里面,会去执行 new MapperFactory().initDataSource(dbConfig),MapperFactory就加载对应的Mapper文件

public abstract class MybatisBundle<T> implements ConfiguredBundle<T> {

    public final void run(T configuration, Environment environment) throws Exception {
        DataSourceFactory dbConfig = getDataSourceFactory(configuration);
        new MapperFactory().initDataSource(dbConfig);
    }

    protected abstract DataSourceFactory getDataSourceFactory(T configuration);

}

3.3 MapperFactory的实现

MapperFactory有个核心的方法initDataSource(),这个方法里面主要做了以下几件事

(1)通过javaAF框架扫描到的database相关配置文件解析到的DataSourceFactory ,将DataSourceFactory 中的数据库相关封装成Properties ,提供给Druid

(2)Druid实现类创建DataSource

(3)通过DataSource创建Configuration (看过mybatis代码应该知道Configuration 在mybatis是一个全局配置类,非常重要)

(4)创建sqlSessionFactory

(5)创建sqlSession 代理(具体看3.4)

(6)将加载好的sqlSession 与sqlSessionFactory加入到HK2容器中

(7)扫描Mapper注解,通过sqlSession 生成Mapper动态代理类,将代理类注入到HK2容器,在Service进行DI的时候就可以直接成功注入。

public class MapperFactory {

    public MapperFactory() {
    }

    private static DataSource dataSource = null;
    private static SqlSessionFactory sqlSessionFactory = null;
    private static Configuration configuration = null;

    public void initDataSource(DataSourceFactory dataSourceFactory) {
        Properties properties = parseDbProperties(dataSourceFactory);
        try {
            if (dataSource == null) {
                dataSource = DruidDataSourceFactory.createDataSource(properties);
                initSqlSessionFactory();
                initMapper();
            }
        } catch (Exception e) {
            log.error("Failed init dataSource", e);
        }
    }

    private Properties parseDbProperties(DataSourceFactory dataSourceFactory) {
        Properties properties = new Properties();
        properties.put(DruidDataSourceFactory.PROP_DRIVERCLASSNAME, dataSourceFactory.getDriverClass());
        properties.put(DruidDataSourceFactory.PROP_URL, dataSourceFactory.getUrl());
        properties.put(DruidDataSourceFactory.PROP_USERNAME, dataSourceFactory.getUser());
        properties.put(DruidDataSourceFactory.PROP_PASSWORD, dataSourceFactory.getPassword());
        return properties;
    }

    private void initSqlSessionFactory() {
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment("development", transactionFactory, dataSource);
        configuration = new MybatisConfiguration(environment);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        ServiceLocator serviceLocator = ServiceLocatorFactory.getInstance().find(ServiceUtils.DW_HK2);
        if (serviceLocator == null) {
            serviceLocator = ServiceLocatorFactory.getInstance().create(ServiceUtils.DW_HK2);
        }
        ServiceLocatorUtilities.addOneConstant(serviceLocator, sqlSessionFactory, "sqlSessionFactory", SqlSessionFactory.class);
        ServiceLocatorUtilities.addOneConstant(serviceLocator, configuration, "configuration", Configuration.class);
    }

    private void initMapper() {
        Set<Class<?>> classes = mapperScanner();
        ServiceLocator serviceLocator = ServiceLocatorFactory.getInstance().find(ServiceUtils.DW_HK2);
        classes.forEach(configuration::addMapper);
        SqlSession sqlSession = new SqlSessionTemplate(sqlSessionFactory);
        classes.forEach(clazz -> ServiceLocatorUtilities.addOneConstant(serviceLocator, sqlSession.getMapper(clazz), clazz.getName(), clazz));
    }

    private Set<Class<?>> mapperScanner() {
        return ScannerUtils.scanByAnnotation(Mapper.class);
    }

3.4 SqlSessionTemplate的实现(进一步优化)

    这里主要就是实现一个动态代理

package com.zte.ums.ume.bn.inventory.otnresmgnt.uniresmanager.mybatis;


import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.List;
import java.util.Map;

import static java.lang.reflect.Proxy.newProxyInstance;
import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;

public class SqlSessionTemplate implements SqlSession {

    private final SqlSessionFactory sqlSessionFactory;

    private final ExecutorType executorType;

    private final SqlSession sqlSessionProxy;


    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
    }


    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
                new Class[]{SqlSession.class}, new SqlSessionInterceptor());
    }

    public SqlSessionFactory getSqlSessionFactory() {
        return this.sqlSessionFactory;
    }

    public ExecutorType getExecutorType() {
        return this.executorType;
    }

    @Override
    public <T> T selectOne(String statement) {
        return this.sqlSessionProxy.selectOne(statement);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        return this.sqlSessionProxy.selectOne(statement, parameter);
    }


    @Override
    public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
        return this.sqlSessionProxy.selectMap(statement, mapKey);
    }

    @Override
    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
        return this.sqlSessionProxy.selectMap(statement, parameter, mapKey);
    }

    @Override
    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
        return this.sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
    }

    @Override
    public <T> Cursor<T> selectCursor(String statement) {
        return this.sqlSessionProxy.selectCursor(statement);
    }


    @Override
    public <T> Cursor<T> selectCursor(String statement, Object parameter) {
        return this.sqlSessionProxy.selectCursor(statement, parameter);
    }

    @Override
    public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
        return this.sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
    }

    @Override
    public <E> List<E> selectList(String statement) {
        return this.sqlSessionProxy.selectList(statement);
    }


    @Override
    public <E> List<E> selectList(String statement, Object parameter) {
        return this.sqlSessionProxy.selectList(statement, parameter);
    }


    @Override
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        return this.sqlSessionProxy.selectList(statement, parameter, rowBounds);
    }

    @Override
    public void select(String statement, ResultHandler handler) {
        this.sqlSessionProxy.select(statement, handler);
    }


    @Override
    public void select(String statement, Object parameter, ResultHandler handler) {
        this.sqlSessionProxy.select(statement, parameter, handler);
    }

    @Override
    public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
        this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
    }

    @Override
    public int insert(String statement) {
        return this.sqlSessionProxy.insert(statement);
    }

    @Override
    public int insert(String statement, Object parameter) {
        return this.sqlSessionProxy.insert(statement, parameter);
    }


    @Override
    public int update(String statement) {
        return this.sqlSessionProxy.update(statement);
    }


    @Override
    public int update(String statement, Object parameter) {
        return this.sqlSessionProxy.update(statement, parameter);
    }

    @Override
    public int delete(String statement) {
        return this.sqlSessionProxy.delete(statement);
    }

    @Override
    public int delete(String statement, Object parameter) {
        return this.sqlSessionProxy.delete(statement, parameter);
    }

    @Override
    public <T> T getMapper(Class<T> type) {
        return getConfiguration().getMapper(type, this);
    }

    @Override
    public void commit() {
        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
    }


    @Override
    public void commit(boolean force) {
        throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
    }

    @Override
    public void rollback() {
        throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
    }

    @Override
    public void rollback(boolean force) {
        throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
    }

    @Override
    public void close() {
        throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");
    }

    @Override
    public void clearCache() {
        this.sqlSessionProxy.clearCache();
    }

    @Override
    public Configuration getConfiguration() {
        return this.sqlSessionFactory.getConfiguration();
    }

    @Override
    public Connection getConnection() {
        return this.sqlSessionProxy.getConnection();
    }

    @Override
    public List<BatchResult> flushStatements() {
        return this.sqlSessionProxy.flushStatements();
    }

    /**
     * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also
     * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to the
     * {@code PersistenceExceptionTranslator}.
     */
    private class SqlSessionInterceptor implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            SqlSession sqlSession = sqlSessionFactory.openSession(executorType, true);
            try {
                Object result = method.invoke(sqlSession, args);
                sqlSession.commit(true);
                return result;
            } catch (Throwable t) {
                Throwable unwrapped = unwrapThrowable(t);
                sqlSession.rollback();
                sqlSession = null;
                throw unwrapped;
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
            }
        }
    }

}

四 案例演示:

(1)实体类

@TableName("demo")
public class Demo {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(2)Rest接口

@Path("/xuyu")
@Contract
public interface DemoApi {

    @POST
    @Path("/add")
    @Consumes({"application/json"})
    @Produces({"application/json"})
    @UnitOfWork
    @io.swagger.annotations.ApiOperation(value = "", notes = "新增或修改基础信息", tags = {"OtnResMgntTopo",})
    @io.swagger.annotations.ApiResponses(value = {
            @io.swagger.annotations.ApiResponse(code = 200, message = "successful operation")})
    Integer addOrUpdateBasicInfo(@ApiParam(value = "待新增或修改的基本信息", required = true) Demo demo
            , @Context HttpServletRequest servletRequest)
            throws Exception;


    @GET
    @Path("/find/{id}")
    @Consumes({"application/json"})
    @Produces({"application/json"})
    @UnitOfWork
    @io.swagger.annotations.ApiOperation(value = "", notes = "新增或修改基础信息", tags = {"OtnResMgntTopo"})
    @io.swagger.annotations.ApiResponses(value = {
            @io.swagger.annotations.ApiResponse(code = 200, message = "successful operation")})
    Demo find(@PathParam(value = "id") String id
            , @Context HttpServletRequest servletRequest)
            throws Exception;

    @POST
    @Path("/delete/{id}")
    @Consumes({"application/json"})
    @Produces({"application/json"})
    @UnitOfWork
    @io.swagger.annotations.ApiOperation(value = "", notes = "新增或修改基础信息", tags = {"OtnResMgntTopo"})
    @io.swagger.annotations.ApiResponses(value = {
            @io.swagger.annotations.ApiResponse(code = 200, message = "successful operation")})
    Integer delete(@PathParam(value = "id") String id
            , @Context HttpServletRequest servletRequest)
            throws Exception;

    @POST
    @Path("/select/{name}")
    @Consumes({"application/json"})
    @Produces({"application/json"})
    @UnitOfWork
    @io.swagger.annotations.ApiOperation(value = "", notes = "新增或修改基础信息", tags = {"OtnResMgntTopo"})
    @io.swagger.annotations.ApiResponses(value = {
            @io.swagger.annotations.ApiResponse(code = 200, message = "successful operation")})
    List<Demo> selectByName(@PathParam(value = "name") String name
            , @Context HttpServletRequest servletRequest)
            throws Exception;


}

(3)定义Mapper接口

    ​这里findDemoByName是通过xml映射得到的,xml文件如下,注意namspace的写法要与接口全路径保持一致

这里额外补充:mybatis-plus自身提高了一些基础的功能在BaseMapper里面,如果需要额外功能就需要自己写XML文件,以及通过注解,这三种方式

@Mapper
public interface DemoMapper extends BaseMapper<Demo> {

    List<Demo> findDemoByName(String name);

}

<?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">
<!--namespace:用来区别不同的类的名字 -->
<mapper namespace="com.zte.sdotn.pg.otnresmgnt.topo.resource.DemoMapper">
    <select id="findDemoByName" parameterType="String" resultType="com.zte.sdotn.pg.otnresmgnt.topo.model.Demo">
        select * from demo where name like #{username}
    </select>
</mapper>

(4)Rest接口实现

@Service
public class DemoImpl implements DemoApi {

    @Inject
    private DemoMapper demoMapper;

    @Override
    public Integer addOrUpdateBasicInfo(Demo demo, HttpServletRequest servletRequest) throws Exception {
        return demoMapper.insert(demo);
    }

    @Override
    public Demo find(String id, HttpServletRequest servletRequest) throws Exception {
        return demoMapper.selectById(id);
    }

    @Override
    public Integer delete(String id, HttpServletRequest servletRequest) throws Exception {
        return demoMapper.deleteById(id);
    }

    @Override
    public List<Demo> selectByName(String name, HttpServletRequest servletRequest) throws Exception {
        return demoMapper.findDemoByName(name);
    }

}

(5)接口访问与数据库

增删改查OK

六 后续改进:
(1)关于动态代理生成sqlSession那块,以及自动提交还需要改进

(2)关于mapper.xml文件的管理,需要统一起来,可以在application.yml进行配置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值