根本简介

Mybatis-Tiny是什么?Mybatis-Tiny是一个基于Mybatis框架的一层极简的扩大,它旨在应用DSL的形式对单表进行CRUD操作,相似于Mybatis-Plus框架,但它绝不是反复造轮子!区别于别的相似框架(如Mybatis-Plus、Fluent-Mybatis等)的实现形式,它采纳一种逆向曲线救国的实现形式,通过较少的代码,极简的扩大实现了相似于他们大多数的性能,齐全满足日常开发中对单表的各种CRUD操作。

我的项目地址:https://github.com/penggle/my...

疾速入门

Talk is cheap,show me the code!
  • 插入操作

    ProductBaseInfo productBase = ...;List<ProductSaleSpec> productSaleSpecs = ...;productBaseInfoMapper.insert(productBase);//基于JDBC-Batch个性的批量插入操作。productSaleSpecMapper.batchUpdate(productSaleSpecs,                                   productSaleSpec -> productSaleSpecMapper.insert(productSaleSpec));//打印日志: - ==>  Preparing: INSERT INTO t_product_base_info( product_id, product_name, product_url, product_tags, product_type, audit_status, online_status, shop_id, remark, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) - ==> Parameters: null, 24期免息【当天发】Huawei/华为Mate40 5G手机官网旗舰店50pro直降mate40e官网30副品4G鸿蒙副品30全网通(String), https://detail.tmall.com/item.htm?id=633658852628(String), ["手机通信","手机","手机"](String), 1(Integer), 0(Integer), 1(Integer), 111212422(Long), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - <==    Updates: 1 - ==>  Preparing: INSERT INTO t_product_sale_spec( product_id, spec_no, spec_name, spec_index, remark, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) - ==> Parameters: 1(Long), 101(String), 4G全网通(String), 1(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 102(String), 5G全网通(String), 2(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 201(String), 亮彩色(String), 1(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 202(String), 釉红色(String), 2(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 203(String), 秘银色(String), 3(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 204(String), 夏日胡杨(String), 4(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 205(String), 秋日胡杨(String), 5(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 301(String), 8+128GB(String), 1(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String) - ==> Parameters: 1(Long), 302(String), 8+256GB(String), 2(Integer), null, 2022-04-27 00:43:42(String), 2022-04-27 00:43:42(String)
  • 更新操作

    //依据ID更新ProductBaseInfo productBase = ...;Map<String,Object> updateColumns1 = MapLambdaBuilder.of(productBase)        //取productBase实例中对应字段的值        .with(ProductBaseInfo::getProductName)        .with(ProductBaseInfo::getRemark)        //如果productBase实例中对应字段的值为空值(null|空串|空数组|空集合)则取default值"1"        .withDefault(ProductBaseInfo::getProductType, 1)        //疏忽productBase实例中对应字段的值,只取override值"0"        .withOverride(ProductBaseInfo::getAuditStatus, 0)        .withOverride(ProductBaseInfo::getOnlineStatus, 0)        .withOverride(ProductBaseInfo::getUpdateTime, DateTimeUtils.formatNow())        .build();productBaseInfoMapper.updateById(productBase.getProductId(), updateColumns1);//实现了畛域实体的identity()办法则productBase.identity()与productBase.getProductId()是等效的//productBaseInfoMapper.updateById(productBase.identity(), updateColumns);//依据条件更新Map<String,Object> updateColumns2 = MapLambdaBuilder.<ProductBaseInfo>ofEmpty()        .withOverride(ProductBaseInfo::getOnlineStatus, 0)        .withOverride(ProductBaseInfo::getUpdateTime, DateTimeUtils.formatNow())        .build();QueryCriteria<ProductBaseInfo> updateCriteria2 = LambdaQueryCriteria.ofSupplier(ProductBaseInfo::new)        .eq(ProductBaseInfo::getProductType, 1)        .in(ProductBaseInfo::getAuditStatus, 0, 1)        .limit(5);productBaseInfoMapper.updateByCriteria(updateCriteria2, updateColumns2);//批量更新List<ProductSaleStock> productSaleStocks = ...;String nowTime = DateTimeUtils.formatNow();productSaleStockMapper.batchUpdate(productSaleStocks, productSaleStock -> {    Map<String,Object> updateColumns = MapLambdaBuilder.of(productSaleStock)        .withOverride(ProductSaleStock::getSellPrice, productSaleStock.getSellPrice() - productSaleStock.getSellPrice() % 100)        .withOverride(ProductSaleStock::getUpdateTime, nowTime)        .build();    //new一个联结主键实例    ID productSaleStockId = new ID()        .addKey(ProductSaleStock::getProductId, productSaleStock.getProductId())        .addKey(ProductSaleStock::getProductId, productSaleStock.getSpecNo());    productSaleStockMapper.updateById(productSaleStockId, updateColumns);    //或者实现了畛域实体的identity()办法,则能够如下间接调用    //productSaleStockMapper.updateById(productSaleStock.identity(), updateColumns);});
  • 查问操作

    //依据ID查ProductBaseInfo productBase1 = productBaseInfoMapper.selectById(1L);ProductBaseInfo productBase2 = productBaseInfoMapper.selectById(10L, new QueryColumns(ProductBaseInfo::getProductId, ProductBaseInfo::getProductName, ProductBaseInfo::getAuditStatus, ProductBaseInfo::getOnlineStatus));ID id = new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "101");ProductSaleSpec productSaleSpec = productSaleSpecMapper.selectById(id);//依据多个ID查问List<ProductBaseInfo> productBases = productBaseInfoMapper.selectListByIds(Arrays.asList(5L, 6L, 7L, 8L, 9L));//依据多个联结主键查问实体对象列表List<ID> ids = new ArrayList<>();ids.add(new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "101"));ids.add(new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "102"));ids.add(new ID().addKey(ProductSaleSpec::getProductId, 1L).addKey(ProductSaleSpec::getSpecNo, "103"));List<ProductSaleSpec> productSaleSpecs = productSaleSpecMapper.selectListByIds(ids); - ==>  Preparing: SELECT product_id AS productId, spec_no AS specNo, spec_name AS specName, spec_index AS specIndex, remark AS remark, DATE_FORMAT(create_time, '%Y-%m-%d %T') AS createTime, DATE_FORMAT(update_time, '%Y-%m-%d %T') AS updateTime FROM t_product_sale_spec WHERE (product_id = ? AND spec_no = ?) OR (product_id = ? AND spec_no = ?) OR (product_id = ? AND spec_no = ?) - ==> Parameters: 1(Long), 101(String), 1(Long), 102(String), 1(Long), 103(String) - <==      Total: 2//依据条件查问QueryCriteria<ProductSaleSpec> queryCriteria1 = LambdaQueryCriteria.ofSupplier(ProductSaleSpec::new)                .eq(ProductSaleSpec::getProductId, 1L)                .eq(ProductSaleSpec::getSpecNo, "101");ProductSaleSpec productSaleSpec = productSaleSpecMapper.selectByCriteria(queryCriteria1);ProductSaleStock queryRequest1 = ...;QueryCriteria<ProductSaleStock> queryCriteria2 = LambdaQueryCriteria.of(queryRequest1)                .eq(ProductSaleStock::getProductId)                .likeRight(ProductSaleStock::getSpecNo)                .between(ProductSaleStock::getStock, queryRequest1.getMinStock(), queryRequest1.getMaxStock())                .orderBy(OrderBy.desc(ProductSaleStock::getSellPrice));List<ProductSaleStock> productStocks = productSaleStockMapper.selectListByCriteria(queryCriteria2);QueryCriteria<ProductBaseInfo> queryCriteria3 = LambdaQueryCriteria.of(queryRequest2)                .and(nestedCriteria -> nestedCriteria.like(ProductBaseInfo::getProductName, "华为")                        .or().like(ProductBaseInfo::getProductName, "HUAWEI"))                .eq(ProductBaseInfo::getProductType)                .eq(ProductBaseInfo::getOnlineStatus)                .in(ProductBaseInfo::getAuditStatus, queryRequest.getAuditStatuses().toArray())                .orderBy(OrderBy.desc(ProductBaseInfo::getCreateTime))                .dynamic(true); //主动过滤掉为空值(null|空串|空数组|空集合)的查问参数List<ProductBaseInfo> productBases1 = productBaseInfoMapper.selectListByCriteria(queryCriteria3);//分页查问1Page page = Page.of(1, 10);QueryCriteria<ProductBaseInfo> queryCriteria4 = LambdaQueryCriteria.of(queryRequest)                .likeRight(ProductBaseInfo::getProductName)                .eq(ProductBaseInfo::getProductType)                .eq(ProductBaseInfo::getOnlineStatus)                .in(ProductBaseInfo::getAuditStatus, queryRequest.getAuditStatuses().toArray())                .orderBy(page.getOrderBys())                .dynamic(true); //主动过滤掉为空值(null|空串|空数组|空集合)的查问参数(条件)List<ProductBaseInfo> productBases2 = productBaseInfoMapper.selectPageListByCriteria(queryCriteria4, new RowBounds(page.offset(), page.limit()));//设置总记录数page.setTotalRowCount(productBaseInfoMapper.selectPageCountByCriteria(queryCriteria4));//分页查问2(等效与下面)Page page = Page.of(2, 10);List<ProductBaseInfo> productBases2 = EntityMapperHelper.selectEntityObjectListByPage(productBaseInfoMapper, queryCriteria4, page);
  • 删除操作

    //依据ID删除productBaseInfoMapper.deleteById(2L);productExtraInfoMapper.deleteById(2L);//依据条件删除QueryCriteria<ProductSaleSpec> queryCriteria1 = LambdaQueryCriteria.ofSupplier(ProductSaleSpec::new)                .eq(ProductSaleSpec::getProductId, 2L)                .limit(5);productSaleSpecMapper.deleteByCriteria(queryCriteria1);
  • 更多示例请见:https://github.com/penggle/my...

个性及限度

  • 反对繁多主键或联结主键,繁多主键时主键策略反对:IDENTITY(数据库自增的),SEQUENCE(基于序列的),NONE(无,客户端本人设置主键)

    反复造轮子的初衷也是被Mybatis-Plus只能应用繁多主键给恶心到了
  • 到目前为止,Mybatis-Tiny没有任何可配置的配置项。Mybatis-Tiny的数据库方言配置与Mybatis自身的方言配置统一,即通过databaseId来实现方言。也就是说Mybatis-Tiny的方言数据库类型取自Configuration.databaseId字段,如果应用程序未设置(通过DatabaseIdProvider来设置),则Mybatis-Tiny会主动设置。

    目前Mybatis-Tiny反对支流的数据库:mysql,mariadb,oracle,db2,sqlserver,postgresql,h2,hsql,sqlite,clickhouse

    对于非主流数据库,可参照非主流数据库方言反对

  • Entity实体类是基于注解的(注解类的设计根本与JPA的注解标准统一);实体类必须实现EntityObject接口,例如:

    @Table("t_product_base_info")public class ProductBaseInfo implements EntityObject {    /** 商品ID */    @Id(strategy=GenerationType.IDENTITY)    private Long productId;    /** 商品名称 */    private String productName;    ...    /** 审核状态:0-待审核,1-审核通过,2-审核不通过 */    private Integer auditStatus;    /** 高低架状态:0-已下架,1-已上架 */    private Integer onlineStatus;        /** 所属店铺ID */    //shopId字段在所有update操作时不会被更新(不在update列中)    @Column(updatable=false)    private Long shopId;    /** 商品备注 */    private String remark;    /** 创立工夫 */    //createTime字段在所有update操作时不会被更新(不在update列中)    @Column(updatable=false, select="DATE_FORMAT({name}, '%Y-%m-%d %T')")    private String createTime;    /** 最近批改工夫 */    @Column(select="DATE_FORMAT({name}, '%Y-%m-%d %T')")    private String updateTime;    //以下属于辅助字段    /** productType的查问后果辅助字段 */    @Transient    private String productTypeName;    /** auditStatus的查问后果辅助字段 */    @Transient    private String auditStatusName;    /** onlineStatus的查问后果辅助字段 */    @Transient    private String onlineStatusName;    /** auditStatus的IN查问条件辅助字段 */    @Transient    private List<Integer> auditStatuses;        //getter/setter...        /**     * 实现该办法是可选的!     *      * 返回畛域实体的主键值,当存在联结主键时,在CRUD时特地有用     * 联结主键(com.penglecode.codeforce.common.domain.ID)     */    @Override    public Long identity() {        return productId;    }    /**     * 实现该办法是可选的!     *     * 这个办法在所有SELECT操作返回后果集前都会由Mybatis     * 插件DomainObjectQueryInterceptor主动执行     *      * 通过实现该办法来实现诸如枚举decode能力     */    @Override    public ProductBaseInfo processOutbound() {        Optional.ofNullable(ProductTypeEnum.of(productType)).map(ProductTypeEnum::getTypeName).ifPresent(this::setProductTypeName);        Optional.ofNullable(ProductAuditStatusEnum.of(auditStatus)).map(ProductAuditStatusEnum::getStatusName).ifPresent(this::setAuditStatusName);        Optional.ofNullable(ProductOnlineStatusEnum.of(onlineStatus)).map(ProductOnlineStatusEnum::getStatusName).ifPresent(this::setOnlineStatusName);        return this;    }    }
  • 反对基于Lambda的DSL形式查问是必须的,例如:

    ProductBaseInfo queryRequest = ...QueryCriteria<ProductBaseInfo> queryCriteria = LambdaQueryCriteria.of(queryRequest)        .likeRight(ProductBaseInfo::getProductName)        .eq(ProductBaseInfo::getProductType)        .eq(ProductBaseInfo::getOnlineStatus, 1) //固定某个查问条件值        .in(ProductBaseInfo::getAuditStatus, queryRequest.getAuditStatuses().toArray())        .orderBy(OrderBy.desc(ProductBaseInfo::getCreateTime))        .limit(5)        .dynamic(true); //主动过滤掉空值(null|空串|空数组|空集合)查问参数;List<ProductBaseInfo> productBases = productBaseInfoMapper.selectListByCriteria(queryCriteria);
  • 反对指定SELECT返回列、UPDATE更新列那都是必须的,例如:

    //更新指定列ProductBaseInfo updateRequest = ...Map<String,Object> updateColumns = MapLambdaBuilder.of(updateRequest)        .with(ProductBaseInfo::getProductName)        .with(ProductBaseInfo::getRemark)        .withDefault(ProductBaseInfo::getProductType, 1)        .withOverride(ProductBaseInfo::getAuditStatus, 0)        .withOverride(ProductBaseInfo::getOnlineStatus, 0)        .withOverride(ProductBaseInfo::getUpdateTime, DateTimeUtils.formatNow())        .build();productBaseInfoMapper.updateById(updateRequest.identity(), updateColumns);//查问返回指定列ProductBaseInfo productBase = productBaseInfoMapper.selectById(1L, new QueryColumns(ProductBaseInfo::getProductId, ProductBaseInfo::getProductName, ProductBaseInfo::getAuditStatus, ProductBaseInfo::getOnlineStatus));
  • 自带基于RowBounds的分页性能,不论是调用BaseEntityMapper#selectPageListByCriteria(QueryCriteria<T>, RowBounds)还是调用自定义的分页查询方法XxxMapper#selectXxxListByPage(Xxx condition, RowBounds)都将会被主动分页,例如:

    public List<ProductBaseInfo> queryProductListByPage(ProductBaseInfo queryRequest, Page page) {    QueryCriteria<ProductBaseInfo>> queryCriteria = LambdaQueryCriteria.of(queryRequest)                .like(ProductBaseInfo::getProductName)                .eq(ProductBaseInfo::getProductType)                .eq(ProductBaseInfo::getOnlineStatus)                .in(ProductBaseInfo::getAuditStatus, queryRequest.getAuditStatuses().toArray())                .orderBy(page.getOrderBys())                .dynamic(true); //主动过滤掉为空值(null|空串|空数组|空集合)的查问参数    List<ProductBaseInfo> productBases = productBaseInfoMapper.selectPageListByCriteria(queryCriteria, new RowBounds(page.offset(), page.limit()));    page.setTotalRowCount(productBaseInfoMapper.selectPageCountByCriteria(queryCriteria)); //设置总记录数    return productBases;}
  • 在Xxx实体对象的XxxMapper中自定义办法必定是能够的:

    见ProductBaseInfoMapper.xml

  • WHERE条件逻辑嵌套查问仅反对嵌套一层(在单表操作中仅反对一层嵌套曾经能满足绝大多数要求了),例如:

    QueryCriteria<ProductBaseInfo> queryCriteria = LambdaQueryCriteria.of(queryRequest)                //仅反对一层嵌套                .and(nestedCriteria -> nestedCriteria.like(ProductBaseInfo::getProductName, "华为")                        .or().like(ProductBaseInfo::getProductName, "HUAWEI"))                .eq(ProductBaseInfo::getProductType)                .eq(ProductBaseInfo::getOnlineStatus)                .in(ProductBaseInfo::getAuditStatus, queryRequest.getAuditStatuses().toArray())                .orderBy(page.getOrderBys())                .dynamic(true); //主动过滤掉为空值(null|空串|空数组|空集合)的查问参数

    下面DSL语句的理论输入SQL如下:

    - ==>  Preparing: SELECT t.product_id productId, t.product_name productName, t.product_type productType, t.audit_status auditStatus, t.online_status onlineStatus FROM t_product_base_info t WHERE ( t.product_name like ? OR t.product_name like ? ) AND t.product_type = ? AND t.audit_status in ( ? , ? , ? ) ORDER BY t.create_time DESC LIMIT 0, 10- ==> Parameters: %华为%(String), %HUAWEI%(String), 1(Integer), 0(Integer), 1(Integer), 2(Integer)- <==      Total: 10
  • 扩大了Mybatis的org.apache.ibatis.executor.Executor,叫DynamicExecutor,用于解决在应用mybatis-spring框架时在同一个事务中不能切换ExecutorType的蛋疼问题(如果你硬要这么做,你将会失去一个异样:'Cannot change the ExecutorType when there is an existing transaction'),这个Mybatis自身设计导致(SqlSession中固化了ExecutorType),派生出DynamicExecutor就是来解决这个问题的。
  • 仅反对单表CRUD操作,不反对多表JOIN,不反对聚合查问(聚合函数+GROUP BY)

    写这个框架的当初初衷仅仅是为了可能省去编写千篇一律的单表CRUD(XxxMapper.xml),如果做多表JOIN及聚合查问的话,则就失去了应用Mybatis的意义了,还不如间接应用JPA。试想你把一个简单查问通过DSL的形式写在JAVA代码中,这跟十多年前在JAVA或者JSP代码中写SQL一样,感觉很恶心。
  • 仅提供了通用的BaseEntityMapper,没有提供BaseService之类的,BaseEntityMapper的办法如下:

  • 反对对BaseEntityMapper的扩大,扩大根底Mapper办法是基于约定的,例如存在这样的扩大:

    package com.penglecode.codeforce.mybatistiny.examples.extensions;import com.penglecode.codeforce.common.domain.EntityObject;import com.penglecode.codeforce.mybatistiny.dsl.QueryColumns;import com.penglecode.codeforce.mybatistiny.mapper.BaseEntityMapper;import org.apache.ibatis.annotations.Param;/** * 加强性能的BaseEntityMapper扩大 * * @author pengpeng * @version 1.0 */public interface EnhancedBaseMapper<T extends EntityObject> extends BaseEntityMapper<T> {    /**     * 通过规范MERGE INTO语句来进行合并存储     *     * @param mergeEntity       - 被更新的实体对象     * @param updateColumns     - 如果是update操作,此参数可指定被更新的列     * @return     */    int merge(@Param("mergeEntity") T mergeEntity, @Param("updateColumns") QueryColumns... updateColumns);}

    基于约定的,你必须在同样package下存在EnhancedBaseMapper.ftl

    Freemarker模板中的预置参数集见EntityMapperTemplateParameter

    OK,这就扩大好了,就是这么简略!

应用形式

Mybatis-Tiny是一层很薄的货色,没有任何个性化的自定义配置,其仅依赖Mybatis自身(不依赖于Spring或SpringBoot)

其Maven依赖:

<dependency>    <groupId>io.github.penggle</groupId>    <artifactId>mybatis-tiny-core</artifactId>    <!-- 版本阐明:3.5指的是基于Mybatis 3.5.x版本的意思 -->    <version>3.5</version></dependency>

上面列举三种应用场景。

  • 只应用Mybatis(无Spring、SpringBoot等大型框架的反对)

    //我不论你其余配置是啥,只有sqlSessionFactory实例是通过DecoratedSqlSessionFactoryBuilder弄出来的就行了!!!SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new DecoratedSqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
  • 仅与Spring框架(精确地说是mybatis-spring)集成应用

    引入相干Maven依赖后在配置类上应用注解@EnableMybatisTiny即可,例如:

    import com.penglecode.codeforce.mybatistiny.EnableMybatisTiny;import com.penglecode.codeforce.mybatistiny.core.DecoratedSqlSessionFactoryBuilder;import com.penglecode.codeforce.mybatistiny.examples.BasePackage;import com.zaxxer.hikari.HikariConfig;import com.zaxxer.hikari.HikariDataSource;import org.apache.commons.lang3.ArrayUtils;import org.apache.ibatis.annotations.Mapper;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.annotation.MapperScan;import org.springframework.context.EnvironmentAware;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration@EnableMybatisTiny@EnableTransactionManagement(proxyTargetClass=true)@MapperScan(basePackageClasses=BasePackage.class, annotationClass=Mapper.class)@ComponentScan(basePackageClasses=BasePackage.class)@PropertySource(value="classpath:application.yml", factory=YamlPropertySourceFactory.class)public class MybatisConfiguration {    @Bean    public DataSource dataSource() {        Properties properties = ...        return new HikariDataSource(new HikariConfig(properties));    }    @Bean    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();        sqlSessionFactoryBean.setDataSource(dataSource);        //这里用不必Mybatis-Tiny提供的DecoratedSqlSessionFactoryBuilder是可选的        //如果不必,在Spring环境下Mybatis-Tiny框架是有应答的补救措施的        //sqlSessionFactoryBean.setSqlSessionFactoryBuilder(new DecoratedSqlSessionFactoryBuilder());        sqlSessionFactoryBean.setConfigLocation(getConfigLocation());        sqlSessionFactoryBean.setTypeAliasesPackage(getTypeAliasesPackage());        sqlSessionFactoryBean.setTypeAliasesSuperType(getTypeAliasesSuperType());        sqlSessionFactoryBean.setMapperLocations(getMapperLocations());        return sqlSessionFactoryBean;    }    @Bean    public DataSourceTransactionManager transactionManager(DataSource dataSource) {        return new DataSourceTransactionManager(dataSource);    }        ...    }
  • 仅与SpringBoot框架(精确地说是mybatis-spring-boot-starter)集成应用

    引入相干Maven依赖后在SpringBoot启动类上应用注解@EnableMybatisTiny即可,例如:

    import com.penglecode.codeforce.mybatistiny.EnableMybatisTiny;import com.penglecode.codeforce.mybatistiny.examples.BasePackage;import org.springframework.boot.autoconfigure.SpringBootApplication;@EnableMybatisTiny@SpringBootApplication(scanBasePackageClasses=BasePackage.class)public class MybatisTinyExampleApplication {    public static void main(String[] args) {        SpringApplication.run(MybatisTinyExampleApplication.class, args);    }}

    mybatis-spring-boot-starterDataSource的配置依旧就好了,application.yml例如:

    #SpringBoot利用的名称spring:    application:        name: mybatis-tiny-examples-springboot    #Hikari 连接池配置    datasource:        hikari:            #连接池名字            pool-name: defaultHikariCP            #最小闲暇连贯数量            minimum-idle: 5            #闲暇连贯存活最大工夫,默认600000(10分钟)            idle-timeout: 180000            #连接池最大连接数,默认是10            maximum-pool-size: 10            #池中连贯的默认主动提交行为,默认值true            auto-commit: true            #池中连贯的最长生命周期,0示意有限生命周期,默认1800000(30分钟)            max-lifetime: 1800000            #期待来自池的连贯的最大毫秒数,默认30000(30秒)            connection-timeout: 30000            #连贯测试语句            connection-test-query: SELECT 1        username: root        password: 123456        url: jdbc:mysql://127.0.0.1:3306/examples?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false&rewriteBatchedStatements=true&useCursorFetch=true#Mybatis-SpringBoot配置mybatis:    config-location: classpath:config/mybatis/mybatis-config.xml    mapper-locations: classpath*:com/penglecode/codeforce/mybatistiny/examples/**/*Mapper.xml    type-aliases-package: com.penglecode.codeforce.mybatistiny.examples    type-aliases-super-type: com.penglecode.codeforce.common.domain.DomainObject
  • 其余框架集成Mybatis-Tiny

    我不论你其余框架具体是啥,只有sqlSessionFactory实例是通过DecoratedSqlSessionFactoryBuilder弄出来的就行了!!!!