支持 solon 启动插件模块结构扩展包

This commit is contained in:
hubin 2024-10-14 22:17:04 +08:00
parent 0995140b94
commit ea714cf111
58 changed files with 1962 additions and 536 deletions

View File

@ -0,0 +1,4 @@
kotlin version: 2.0.20
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
1. Kotlin compile daemon is ready

View File

@ -0,0 +1,5 @@
- opt: 优化代码生成器支持可视化配置生产能力
- opt: 解构扩展包不再强制依赖 spring 开发框架
- feat: 重构 service 模块抽象为 CrudRepository 不再建议使用 IService 避免业务层数据混乱
- feat: 新增 solon 启动插件支持

View File

@ -1,4 +1,4 @@
APP_VERSION=3.5.8
APP_VERSION=3.5.9
APP_GROUP=com.baomidou
signing.keyId=1FD337F9
signing.password=243194995

View File

@ -1,7 +1,6 @@
package com.baomidou.mybatisplus.test.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.test.entity.AEntity;
import com.baomidou.mybatisplus.test.entity.BEntity;
public interface BMapper extends BaseMapper<BEntity> {

View File

@ -6,12 +6,9 @@ compileKotlin{
dependencies {
api project(":mybatis-plus-core")
implementation "${lib."mybatis-spring"}"
implementation "${lib."kotlin-stdlib-jdk8"}"
implementation "${lib."kotlin-reflect"}"
implementation "${lib."spring-context-support"}"
implementation "${lib."spring-jdbc"}"
implementation "${lib."slf4j-api"}"
implementation "${lib."p6spy"}"
implementation "${lib."jackson"}"

View File

@ -21,11 +21,10 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionUtils;
import java.io.Serializable;
import java.util.List;
@ -43,11 +42,11 @@ import java.util.Objects;
* @author hubin
* @since 2016-11-06
*/
public abstract class Model<T extends Model<?>> implements Serializable {
public abstract class AbstractModel<T extends AbstractModel<?>> implements Serializable {
private static final long serialVersionUID = 1L;
private final transient Class<?> entityClass = this.getClass();
protected final transient Class<?> entityClass = this.getClass();
/**
* 插入字段选择插入
@ -237,13 +236,6 @@ public abstract class Model<T extends Model<?>> implements Serializable {
}
}
/**
* 执行 SQL
*/
public SqlRunner sql() {
return new SqlRunner(this.entityClass);
}
/**
* 获取Session 默认自动提交
*/
@ -284,6 +276,6 @@ public abstract class Model<T extends Model<?>> implements Serializable {
* @param sqlSession session
*/
protected void closeSqlSession(SqlSession sqlSession) {
SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(this.entityClass));
CompatibleHelper.getCompatibleSet().closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(this.entityClass));
}
}

View File

@ -17,17 +17,13 @@ package com.baomidou.mybatisplus.extension.ddl;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.ddl.history.IDdlGenerator;
import com.baomidou.mybatisplus.extension.ddl.history.MysqlDdlGenerator;
import com.baomidou.mybatisplus.extension.ddl.history.OracleDdlGenerator;
import com.baomidou.mybatisplus.extension.ddl.history.PostgreDdlGenerator;
import com.baomidou.mybatisplus.extension.ddl.history.SQLiteDdlGenerator;
import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
import com.baomidou.mybatisplus.extension.ddl.history.*;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.apache.ibatis.jdbc.SqlRunner;
import org.springframework.core.io.ClassPathResource;
import javax.sql.DataSource;
import java.io.*;
@ -126,7 +122,7 @@ public class DdlHelper {
}
public static InputStream getInputStream(String path) throws Exception {
return new ClassPathResource(path).getInputStream();
return CompatibleHelper.getCompatibleSet().getInputStream(path);
}
protected static String getNowTime() {

View File

@ -0,0 +1,128 @@
package com.baomidou.mybatisplus.extension.repository;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.override.MybatisMapperProxy;
import com.baomidou.mybatisplus.core.toolkit.MybatisUtils;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
public abstract class AbstractRepository<M extends BaseMapper<T>, T> implements IRepository<T> {
protected final Log log = LogFactory.getLog(getClass());
/**
* @see #getEntityClass()
*/
private Class<T> entityClass;
@Override
public Class<T> getEntityClass() {
if(this.entityClass == null) {
this.entityClass = (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getMapperClass(), BaseMapper.class)[0];
}
return this.entityClass;
}
/**
* @see #getMapperClass()
*/
private Class<M> mapperClass;
private volatile SqlSessionFactory sqlSessionFactory;
protected SqlSessionFactory getSqlSessionFactory() {
if (this.sqlSessionFactory == null) {
MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
this.sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
}
return this.sqlSessionFactory;
}
/**
* @return baseMapper 真实类型
* @since 3.5.7
*/
public Class<M> getMapperClass() {
if (this.mapperClass == null) {
MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
this.mapperClass = (Class<M>) mybatisMapperProxy.getMapperInterface();
}
return this.mapperClass;
}
/**
* TableId 注解存在更新记录否插入一条记录
*
* @param entity 实体对象
* @return boolean
*/
@Override
public boolean saveOrUpdate(T entity) {
return getBaseMapper().insertOrUpdate(entity);
}
@Override
public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
return getBaseMapper().selectOne(queryWrapper, throwEx);
}
@Override
public Optional<T> getOneOpt(Wrapper<T> queryWrapper, boolean throwEx) {
return Optional.ofNullable(getBaseMapper().selectOne(queryWrapper, throwEx));
}
@Override
public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
return SqlHelper.getObject(log, getBaseMapper().selectMaps(queryWrapper));
}
@Override
public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
return SqlHelper.getObject(log, listObjs(queryWrapper, mapper));
}
/**
* 执行批量操作
*
* @param list 数据集合
* @param batchSize 批量大小
* @param consumer 执行方法
* @param <E> 泛型
* @return 操作结果
* @since 3.3.1
*/
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
return SqlHelper.executeBatch(getSqlSessionFactory(), this.log, list, batchSize, consumer);
}
/**
* 执行批量操作默认批次提交数量{@link IRepository#DEFAULT_BATCH_SIZE}
*
* @param list 数据集合
* @param consumer 执行方法
* @param <E> 泛型
* @return 操作结果
* @since 3.3.1
*/
protected <E> boolean executeBatch(Collection<E> list, BiConsumer<SqlSession, E> consumer) {
return executeBatch(list, DEFAULT_BATCH_SIZE, consumer);
}
@Override
public boolean removeById(Serializable id, boolean useFill) {
return SqlHelper.retBool(getBaseMapper().deleteById(id, useFill));
}
}

View File

@ -1,19 +1,4 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.service;
package com.baomidou.mybatisplus.extension.repository;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@ -22,30 +7,21 @@ import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.ChainQuery;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.ChainUpdate;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.kotlin.KtQueryChainWrapper;
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 顶级 Service
*
* @author hubin
* @since 2018-06-23
*/
public interface IService<T> {
public interface IRepository<T> {
/**
* 默认批次提交数量
@ -61,16 +37,6 @@ public interface IService<T> {
return SqlHelper.retBool(getBaseMapper().insert(entity));
}
/**
* 插入批量
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveBatch(Collection<T> entityList) {
return saveBatch(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 插入批量
*
@ -79,16 +45,6 @@ public interface IService<T> {
*/
boolean saveBatch(Collection<T> entityList, int batchSize);
/**
* 批量修改插入
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 批量修改插入
*
@ -174,59 +130,6 @@ public interface IService<T> {
return SqlHelper.retBool(getBaseMapper().deleteByIds(list, useFill));
}
/**
* 批量删除(jdbc批量提交)
*
* @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
* @return 删除结果
* @since 3.5.0
*/
@Transactional(rollbackFor = Exception.class)
default boolean removeBatchByIds(Collection<?> list) {
return removeBatchByIds(list, DEFAULT_BATCH_SIZE);
}
/**
* 批量删除(jdbc批量提交)
*
* @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
* @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除)
* @return 删除结果
* @since 3.5.0
*/
default boolean removeBatchByIds(Collection<?> list, boolean useFill) {
return removeBatchByIds(list, DEFAULT_BATCH_SIZE, useFill);
}
/**
* 批量删除(jdbc批量提交)
*
* @param list 主键ID或实体列表
* @param batchSize 批次大小
* @return 删除结果
* @since 3.5.0
* @deprecated 3.5.7 {@link #removeBatchByIds(Collection)}
*/
@Deprecated
default boolean removeBatchByIds(Collection<?> list, int batchSize) {
throw new UnsupportedOperationException("不支持的方法!");
}
/**
* 批量删除(jdbc批量提交)
*
* @param list 主键ID或实体列表
* @param batchSize 批次大小
* @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除)
* @return 删除结果
* @since 3.5.0
* @deprecated 3.5.7 {@link #removeBatchByIds(Collection)}
*/
@Deprecated
default boolean removeBatchByIds(Collection<?> list, int batchSize, boolean useFill) {
throw new UnsupportedOperationException("不支持的方法!");
}
/**
* 根据 ID 选择修改
*
@ -256,16 +159,6 @@ public interface IService<T> {
return SqlHelper.retBool(getBaseMapper().update(entity, updateWrapper));
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 根据ID 批量更新
*
@ -570,20 +463,24 @@ public interface IService<T> {
*/
Class<T> getEntityClass();
/**
/*
* 以下的方法使用介绍:
*
* <p>
* . 名称介绍
* 1. 方法名带有 query 的为对数据的查询操作, 方法名带有 update 的为对数据的修改操作
* 2. 方法名带有 lambda 的为内部方法入参 column 支持函数式的
* </p>
* <p>
* . 支持介绍
*
* 1. 方法名带有 query 的支持以 {@link ChainQuery} 内部的方法名结尾进行数据查询操作
* 2. 方法名带有 update 的支持以 {@link ChainUpdate} 内部的方法名为结尾进行数据修改操作
* </p>
*
* <p>
* . 使用示例,只用不带 lambda 的方法各展示一个例子,其他类推
* 1. 根据条件获取一条数据: `query().eq("column", value).one()`
* 2. 根据条件删除一条数据: `update().eq("column", value).remove()`
* </p>
*
*/
@ -655,23 +552,4 @@ public interface IService<T> {
default LambdaUpdateChainWrapper<T> lambdaUpdate() {
return ChainWrappers.lambdaUpdateChain(getBaseMapper());
}
/**
* <p>
* 根据updateWrapper尝试更新否继续执行saveOrUpdate(T)方法
* 此次修改主要是减少了此项业务代码的代码量存在性验证之后的saveOrUpdate操作
* </p>
* <p>
* 该方法不推荐在多线程并发下使用并发可能存在间隙锁的问题可以采用先查询后判断是否更新或保存
* </p>
* <p>
* 该方法存在安全隐患将在后续大版本删除
* </p>
*
* @param entity 实体对象
*/
@Deprecated
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
return update(entity, updateWrapper) || saveOrUpdate(entity);
}
}

View File

@ -1,310 +0,0 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.override.MybatisMapperProxy;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* IService 实现类 泛型M mapper 对象T 是实体
*
* @author hubin
* @since 2018-06-23
*/
@SuppressWarnings("unchecked")
public abstract class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
protected final Log log = LogFactory.getLog(getClass());
@Autowired
protected M baseMapper;
@Override
public M getBaseMapper() {
Assert.notNull(this.baseMapper, "baseMapper can not be null");
return this.baseMapper;
}
/**
* @see #getEntityClass()
*/
private Class<T> entityClass;
@Override
public Class<T> getEntityClass() {
if(this.entityClass == null) {
this.entityClass = (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getMapperClass(), BaseMapper.class)[0];
}
return this.entityClass;
}
/**
* @see #currentMapperClass()
*/
private Class<M> mapperClass;
private volatile SqlSessionFactory sqlSessionFactory;
protected SqlSessionFactory getSqlSessionFactory() {
if (this.sqlSessionFactory == null) {
MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
this.sqlSessionFactory = MybatisUtils.getSqlSessionFactory(mybatisMapperProxy);
}
return this.sqlSessionFactory;
}
/**
* 判断数据库操作是否成功
*
* @param result 数据库操作返回影响条数
* @return boolean
* @deprecated 3.3.1
*/
@Deprecated
protected boolean retBool(Integer result) {
return SqlHelper.retBool(result);
}
/**
* @return baseMapper 真实类型
* @deprecated 3.5.7 {@link #getMapperClass()}
*/
@Deprecated
protected Class<M> currentMapperClass() {
return this.getMapperClass();
}
/**
* @return baseMapper 真实类型
* @since 3.5.7
*/
public Class<M> getMapperClass() {
if (this.mapperClass == null) {
MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this.getBaseMapper());
this.mapperClass = (Class<M>) mybatisMapperProxy.getMapperInterface();
}
return this.mapperClass;
}
/**
* @return 实体类型
* @deprecated 3.5.7 {@link #getEntityClass()}
*/
@Deprecated
protected Class<T> currentModelClass() {
return getEntityClass();
}
/**
* 批量操作 SqlSession
*
* @deprecated 3.3.0
*/
@Deprecated
protected SqlSession sqlSessionBatch() {
return getSqlSessionFactory().openSession(ExecutorType.BATCH);
}
/**
* 释放sqlSession
*
* @param sqlSession session
* @deprecated 3.3.0
*/
@Deprecated
protected void closeSqlSession(SqlSession sqlSession) {
SqlSessionUtils.closeSqlSession(sqlSession, getSqlSessionFactory());
}
/**
* 获取 SqlStatement
*
* @param sqlMethod ignore
* @return ignore
* @see #getSqlStatement(SqlMethod)
* @deprecated 3.4.0
*/
@Deprecated
protected String sqlStatement(SqlMethod sqlMethod) {
return SqlHelper.table(getEntityClass()).getSqlStatement(sqlMethod.getMethod());
}
/**
* 批量插入
*
* @param entityList ignore
* @param batchSize ignore
* @return ignore
*/
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
}
/**
* 获取mapperStatementId
*
* @param sqlMethod 方法名
* @return 命名id
* @since 3.4.0
*/
protected String getSqlStatement(SqlMethod sqlMethod) {
return SqlHelper.getSqlStatement(this.currentMapperClass(), sqlMethod);
}
/**
* TableId 注解存在更新记录否插入一条记录
*
* @param entity 实体对象
* @return boolean
*/
@Override
public boolean saveOrUpdate(T entity) {
return getBaseMapper().insertOrUpdate(entity);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass());
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
return SqlHelper.saveOrUpdateBatch(getSqlSessionFactory(), this.currentMapperClass(), this.log, entityList, batchSize, (sqlSession, entity) -> {
Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
return StringUtils.checkValNull(idVal)
|| CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
}, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
});
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(sqlStatement, param);
});
}
@Override
public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
return getBaseMapper().selectOne(queryWrapper, throwEx);
}
@Override
public Optional<T> getOneOpt(Wrapper<T> queryWrapper, boolean throwEx) {
return Optional.ofNullable(getBaseMapper().selectOne(queryWrapper, throwEx));
}
@Override
public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
return SqlHelper.getObject(log, getBaseMapper().selectMaps(queryWrapper));
}
@Override
public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
return SqlHelper.getObject(log, listObjs(queryWrapper, mapper));
}
/**
* 执行批量操作
*
* @param consumer consumer
* @since 3.3.0
* @deprecated 3.3.1 后面我打算移除掉 {@link #executeBatch(Collection, int, BiConsumer)} }.
*/
@Deprecated
protected boolean executeBatch(Consumer<SqlSession> consumer) {
return SqlHelper.executeBatch(getSqlSessionFactory(), this.log, consumer);
}
/**
* 执行批量操作
*
* @param list 数据集合
* @param batchSize 批量大小
* @param consumer 执行方法
* @param <E> 泛型
* @return 操作结果
* @since 3.3.1
*/
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
return SqlHelper.executeBatch(getSqlSessionFactory(), this.log, list, batchSize, consumer);
}
/**
* 执行批量操作默认批次提交数量{@link IService#DEFAULT_BATCH_SIZE}
*
* @param list 数据集合
* @param consumer 执行方法
* @param <E> 泛型
* @return 操作结果
* @since 3.3.1
*/
protected <E> boolean executeBatch(Collection<E> list, BiConsumer<SqlSession, E> consumer) {
return executeBatch(list, DEFAULT_BATCH_SIZE, consumer);
}
@Override
public boolean removeById(Serializable id, boolean useFill) {
return SqlHelper.retBool(getBaseMapper().deleteById(id, useFill));
}
@Override
public boolean removeBatchByIds(Collection<?> list, int batchSize) {
return SqlHelper.retBool(getBaseMapper().deleteByIds(list));
}
@Override
public boolean removeBatchByIds(Collection<?> list, int batchSize, boolean useFill) {
return SqlHelper.retBool(getBaseMapper().deleteByIds(list, useFill));
}
}

View File

@ -21,18 +21,12 @@ import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.SneakyThrows;
import org.apache.ibatis.exceptions.PersistenceException;
import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionHolder;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.sql.Statement;
import java.util.Collection;
@ -92,7 +86,7 @@ public final class SqlHelper {
*/
@Deprecated
public static SqlSession sqlSession(Class<?> clazz) {
return SqlSessionUtils.getSqlSession(GlobalConfigUtils.currentSessionFactory(clazz));
return CompatibleHelper.getCompatibleSet().getSqlSession(GlobalConfigUtils.currentSessionFactory(clazz));
}
/**
@ -188,40 +182,8 @@ public final class SqlHelper {
return executeBatch(sqlSessionFactory(entityClass), log, consumer);
}
@SneakyThrows
public static boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer) {
SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
if (sqlSessionHolder != null) {
SqlSession sqlSession = sqlSessionHolder.getSqlSession();
//原生无法支持执行器切换当存在批量操作时会嵌套两个session的优先commit上一个session
//按道理来说这里的值应该一直为false
sqlSession.commit(!transaction);
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
if (!transaction) {
log.warn("SqlSession [" + sqlSession + "] Transaction not enabled");
}
try {
consumer.accept(sqlSession);
//非事务情况下强制commit
sqlSession.commit(!transaction);
return true;
} catch (Throwable t) {
sqlSession.rollback();
Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
if (unwrapped instanceof PersistenceException) {
MyBatisExceptionTranslator myBatisExceptionTranslator
= new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
Throwable throwable = myBatisExceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (throwable != null) {
throw throwable;
}
}
throw ExceptionUtils.mpe(unwrapped);
} finally {
sqlSession.close();
}
return CompatibleHelper.getCompatibleSet().executeBatch(sqlSessionFactory, log, consumer);
}
/**
@ -318,9 +280,9 @@ public final class SqlHelper {
* {@code
* SqlSession sqlSession = SqlHelper.sqlSession(entityClass);
* try {
* BaseMapper<User> userMapper = getMapper(User.class, sqlSession);
* BaseMapper<User> userMapper = getMapper(User.class, sqlSession);
* } finally {
* sqlSession.close();
* sqlSession.close();
* }
* }
*
@ -330,7 +292,7 @@ public final class SqlHelper {
* @return Mapper
*/
@SuppressWarnings("unchecked")
public static <T,M extends BaseMapper<T>> M getMapper(Class<T> entityClass, SqlSession sqlSession) {
public static <T, M extends BaseMapper<T>> M getMapper(Class<T> entityClass, SqlSession sqlSession) {
Assert.notNull(entityClass, "entityClass can't be null!");
TableInfo tableInfo = Optional.ofNullable(TableInfoHelper.getTableInfo(entityClass)).orElseThrow(() -> ExceptionUtils.mpe("Can not find TableInfo from Class: \"%s\".", entityClass.getName()));
Class<?> mapperClass = ClassUtils.toClassConfident(tableInfo.getCurrentNamespace());
@ -347,12 +309,12 @@ public final class SqlHelper {
* @param <M> Mapper类型
* @return 返回lambda执行结果
*/
public static <T, R,M extends BaseMapper<T>> R execute(Class<T> entityClass, SFunction<M, R> sFunction) {
public static <T, R, M extends BaseMapper<T>> R execute(Class<T> entityClass, SFunction<M, R> sFunction) {
SqlSession sqlSession = SqlHelper.sqlSession(entityClass);
try {
return sFunction.apply(SqlHelper.getMapper(entityClass, sqlSession));
} finally {
SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(entityClass));
CompatibleHelper.getCompatibleSet().closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(entityClass));
}
}
}

View File

@ -17,7 +17,6 @@ package com.baomidou.mybatisplus.generator.config.po;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
@ -229,7 +228,7 @@ public class TableInfo {
} else {
if (entity.isActiveRecord()) {
// 无父类开启 AR 模式
this.importPackages.add(Model.class.getCanonicalName());
this.importPackages.add("com.baomidou.mybatisplus.extension.activerecord.Model");
}
}
if (entity.isSerialVersionUID() || entity.isActiveRecord()) {

View File

@ -0,0 +1,17 @@
apply plugin: 'kotlin'
compileKotlin{
kotlinOptions.jvmTarget = "1.8"
}
dependencies {
api project(":mybatis-plus-extension")
api "org.noear:mybatis-solon-plugin:3.0.0"
api "org.noear:solon-aot:3.0.0"
testImplementation "org.noear:solon-test:3.0.0"
testImplementation "io.github.classgraph:classgraph:4.8.176"
testImplementation "com.zaxxer:HikariCP:4.0.3"
testImplementation "${lib.h2}"
testImplementation "${lib.mysql}"
testImplementation "${lib.'logback-classic'}"
}

View File

@ -0,0 +1,33 @@
package com.baomidou.mybatisplus.core.override;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.lang.reflect.Method;
public class SolonMybatisMapperProxy<T> extends MybatisMapperProxy<T> {
private final SqlSessionFactory factory;
private final Class<T> mapperInterface;
private final SqlSession sqlSession;
public SolonMybatisMapperProxy(SqlSessionFactory sqlSessionFactory, SqlSession sqlSession, Class<T> mapperInterface) {
super(null, mapperInterface, null);
this.factory = sqlSessionFactory;
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
}
@Override
public SqlSession getSqlSession() {
return sqlSession;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try (SqlSession session = factory.openSession(true)) {
Object mapper = session.getMapper(mapperInterface);
return method.invoke(mapper, args);
}
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.activerecord;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
/**
* ActiveRecord 模式 CRUD
* <p>
* 必须存在对应的原始mapper并继承baseMapper并且可以使用的前提下
* 才能使用此 AR 模式 !!!
* </p>
*
* @param <T>
* @author hubin
* @since 2016-11-06
*/
public abstract class Model<T extends Model<?>> extends AbstractModel<T> {
/**
* 执行 SQL
*/
public SqlRunner sql() {
return new SqlRunner(this.entityClass);
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.compatible;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.noear.solon.core.util.GenericUtil;
import org.noear.solon.core.util.ResourceUtil;
import org.noear.solon.data.tran.TranUtils;
import java.io.InputStream;
import java.util.function.Consumer;
/**
* spring 兼容方法集接口实现类
*/
public class SolonCompatibleSet implements CompatibleSet {
@Override
public SqlSession getSqlSession(SqlSessionFactory sessionFactory) {
return sessionFactory.openSession();
}
@Override
public void closeSqlSession(SqlSession sqlSession, SqlSessionFactory sqlSessionFactory) {
if (sqlSession != null) {
sqlSession.close();
}
}
@Override
public boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer) {
boolean transaction = TranUtils.inTrans();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
if (!transaction) {
log.warn("SqlSession [" + sqlSession + "] Transaction not enabled");
}
try {
consumer.accept(sqlSession);
//非事务情况下强制commit
sqlSession.commit(!transaction);
return true;
} catch (RuntimeException t) {
throw t;
} catch (Throwable t) {
sqlSession.rollback();
Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
if (unwrapped instanceof RuntimeException) {
throw (RuntimeException) unwrapped;
} else {
throw ExceptionUtils.mpe(unwrapped);
}
} finally {
sqlSession.close();
}
}
@Override
public InputStream getInputStream(String path) throws Exception {
return ResourceUtil.findResource(path).openStream();
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.ddl;
import org.noear.solon.annotation.Inject;
import javax.sql.DataSource;
import java.util.List;
import java.util.function.Consumer;
/**
* 非多数据源 DDL 实现
*
* @author hubin
* @since 2021-09-23
*/
public class SimpleDdl implements IDdl {
@Inject
private DataSource dataSource;
@Override
public void runScript(Consumer<DataSource> consumer) {
consumer.accept(dataSource);
}
@Override
public List<String> getSqlFiles() {
return null;
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.repository;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.binding.MapperMethod;
import org.noear.solon.annotation.Inject;
import org.noear.solon.data.annotation.Tran;
import java.util.Collection;
/**
* IService 实现类 泛型M mapper 对象T 是实体
*
* @author hubin
* @since 2018-06-23
*/
public abstract class CrudRepository<M extends BaseMapper<T>, T> extends AbstractRepository<M, T> {
@Inject
protected M baseMapper;
@Override
public M getBaseMapper() {
Assert.notNull(this.baseMapper, "baseMapper can not be null");
return this.baseMapper;
}
/**
* 批量插入
*
* @param entityList ignore
* @param batchSize ignore
* @return ignore
*/
@Tran
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
}
/**
* 获取mapperStatementId
*
* @param sqlMethod 方法名
* @return 命名id
* @since 3.4.0
*/
protected String getSqlStatement(SqlMethod sqlMethod) {
return SqlHelper.getSqlStatement(this.getMapperClass(), sqlMethod);
}
@Tran
@Override
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass());
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
return SqlHelper.saveOrUpdateBatch(getSqlSessionFactory(), this.getMapperClass(), this.log, entityList, batchSize, (sqlSession, entity) -> {
Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
return StringUtils.checkValNull(idVal)
|| CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
}, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
});
}
@Tran
@Override
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(sqlStatement, param);
});
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.service;
import com.baomidou.mybatisplus.extension.repository.IRepository;
import org.noear.solon.data.annotation.Tran;
import java.util.Collection;
/**
* 顶级 Service
*
* @author hubin
* @since 2018-06-23
*/
public interface IService<T> extends IRepository<T> {
/**
* 插入批量
*
* @param entityList 实体对象集合
*/
@Tran
default boolean saveBatch(Collection<T> entityList) {
return saveBatch(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 批量修改插入
*
* @param entityList 实体对象集合
*/
@Tran
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 批量删除(jdbc批量提交)
*
* @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
* @return 删除结果
* @since 3.5.0
*/
@Tran
default boolean removeBatchByIds(Collection<?> list) {
return removeByIds(list);
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
*/
@Tran
default boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.service.impl;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* IService 实现类 泛型M mapper 对象T 是实体
*
* @author hubin
* @since 2018-06-23
*/
public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T> implements IService<T> {
}

View File

@ -0,0 +1,244 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.toolkit;
import com.baomidou.mybatisplus.core.assist.ISqlRunner;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.noear.solon.data.annotation.Tran;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* SqlRunner 执行 SQL
*
* @author Caratacus
* @since 2016-12-11
*/
public class SqlRunner implements ISqlRunner {
// 单例Query
public static final SqlRunner DEFAULT = new SqlRunner();
private final Log log = LogFactory.getLog(SqlRunner.class);
private Class<?> clazz;
public SqlRunner() {
}
public SqlRunner(Class<?> clazz) {
this.clazz = clazz;
}
/**
* 获取默认的SqlQuery(适用于单库)
*
* @return ignore
*/
public static SqlRunner db() {
return DEFAULT;
}
/**
* 根据当前class对象获取SqlQuery(适用于多库)
*
* @param clazz ignore
* @return ignore
*/
public static SqlRunner db(Class<?> clazz) {
return new SqlRunner(clazz);
}
@Tran
@Override
public boolean insert(String sql, Object... args) {
SqlSession sqlSession = sqlSession();
try {
return SqlHelper.retBool(sqlSession.insert(INSERT, sqlMap(sql, args)));
} finally {
closeSqlSession(sqlSession);
}
}
@Tran
@Override
public boolean delete(String sql, Object... args) {
SqlSession sqlSession = sqlSession();
try {
return SqlHelper.retBool(sqlSession.delete(DELETE, sqlMap(sql, args)));
} finally {
closeSqlSession(sqlSession);
}
}
/**
* 获取sqlMap参数
*
* @param sql 指定参数的格式: {0}, {1}
* @param args 仅支持String
* @return ignore
*/
private Map<String, String> sqlMap(String sql, Object... args) {
Map<String, String> sqlMap = CollectionUtils.newHashMapWithExpectedSize(1);
sqlMap.put(SQL, StringUtils.sqlArgsFill(sql, args));
return sqlMap;
}
/**
* 获取sqlMap参数
*
* @param sql 指定参数的格式: {0}, {1}
* @param page 分页模型
* @param args 仅支持String
* @return ignore
*/
private Map<String, Object> sqlMap(String sql, IPage<?> page, Object... args) {
Map<String, Object> sqlMap = CollectionUtils.newHashMapWithExpectedSize(2);
sqlMap.put(PAGE, page);
sqlMap.put(SQL, StringUtils.sqlArgsFill(sql, args));
return sqlMap;
}
@Tran
@Override
public boolean update(String sql, Object... args) {
SqlSession sqlSession = sqlSession();
try {
return SqlHelper.retBool(sqlSession.update(UPDATE, sqlMap(sql, args)));
} finally {
closeSqlSession(sqlSession);
}
}
/**
* 根据sql查询Map结果集
* <p>SqlRunner.db().selectList("select * from tbl_user where name={0}", "Caratacus")</p>
*
* @param sql sql语句可添加参数格式{0},{1}
* @param args 只接受String格式
* @return ignore
*/
@Override
public List<Map<String, Object>> selectList(String sql, Object... args) {
SqlSession sqlSession = sqlSession();
try {
return sqlSession.selectList(SELECT_LIST, sqlMap(sql, args));
} finally {
closeSqlSession(sqlSession);
}
}
/**
* 根据sql查询一个字段值的结果集
* <p>注意该方法只会返回一个字段的值 如果需要多字段请参考{@code selectList()}</p>
*
* @param sql sql语句可添加参数格式{0},{1}
* @param args 只接受String格式
* @return ignore
*/
@Override
public List<Object> selectObjs(String sql, Object... args) {
SqlSession sqlSession = sqlSession();
try {
return sqlSession.selectList(SELECT_OBJS, sqlMap(sql, args));
} finally {
closeSqlSession(sqlSession);
}
}
/**
* 根据sql查询一个字段值的一条结果
* <p>注意该方法只会返回一个字段的值 如果需要多字段请参考{@code selectOne()}</p>
*
* @param sql sql语句可添加参数格式{0},{1}
* @param args 只接受String格式
* @return ignore
*/
@Override
public Object selectObj(String sql, Object... args) {
return SqlHelper.getObject(log, selectObjs(sql, args));
}
@Override
public long selectCount(String sql, Object... args) {
SqlSession sqlSession = sqlSession();
try {
return SqlHelper.retCount(sqlSession.<Long>selectOne(COUNT, sqlMap(sql, args)));
} finally {
closeSqlSession(sqlSession);
}
}
@Override
public Map<String, Object> selectOne(String sql, Object... args) {
return SqlHelper.getObject(log, selectList(sql, args));
}
@Override
public <E extends IPage<Map<String, Object>>> E selectPage(E page, String sql, Object... args) {
if (null == page) {
return null;
}
SqlSession sqlSession = sqlSession();
try {
page.setRecords(sqlSession.selectList(SELECT_LIST, sqlMap(sql, page, args)));
} finally {
closeSqlSession(sqlSession);
}
return page;
}
/**
* 获取Session 默认自动提交
*/
private SqlSession sqlSession() {
return getSqlSessionFactory().openSession();
}
/**
* 释放sqlSession
*
* @param sqlSession session
*/
private void closeSqlSession(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.close();
}
}
/**
* 获取SqlSessionFactory
*/
private SqlSessionFactory getSqlSessionFactory() {
return Optional.ofNullable(clazz).map(GlobalConfigUtils::currentSessionFactory).orElse(SqlHelper.FACTORY);
}
/**
* @deprecated 3.5.3.2
*/
@Deprecated
public void close() {
}
}

View File

@ -0,0 +1,24 @@
package com.baomidou.mybatisplus.solon.integration;
import org.apache.ibatis.solon.MybatisAdapter;
import org.apache.ibatis.solon.MybatisAdapterFactory;
import org.noear.solon.core.BeanWrap;
import org.noear.solon.core.Props;
/**
* 适配器工厂 for mybatis-plus
*
* @author noear, iYarnFog
* @since 1.5
*/
public class MybatisAdapterFactoryPlus implements MybatisAdapterFactory {
@Override
public MybatisAdapter create(BeanWrap dsWrap) {
return new MybatisAdapterPlus(dsWrap);
}
@Override
public MybatisAdapter create(BeanWrap dsWrap, Props dsProps) {
return new MybatisAdapterPlus(dsWrap, dsProps);
}
}

View File

@ -0,0 +1,146 @@
package com.baomidou.mybatisplus.solon.integration;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.override.SolonMybatisMapperProxy;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.solon.integration.MybatisAdapterDefault;
import org.noear.solon.Utils;
import org.noear.solon.core.BeanWrap;
import org.noear.solon.core.Props;
import org.noear.solon.core.VarHolder;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
/**
* 适配器 for mybatis-plus
* <p>
* 1.提供 mapperScan 能力
* 2.生成 factory 的能力
*
* @author noear, iYarnFog
* @since 1.5
*/
public class MybatisAdapterPlus extends MybatisAdapterDefault {
MybatisSqlSessionFactoryBuilder factoryBuilderPlus;
GlobalConfig globalConfig;
SqlSession sqlSession;
Map<Class<?>, Object> mapperCached = new HashMap<>();
/**
* 构建Sql工厂适配器使用默认的 typeAliases mappers 配置
*/
protected MybatisAdapterPlus(BeanWrap dsWrap) {
super(dsWrap);
this.factoryBuilderPlus = new MybatisSqlSessionFactoryBuilder();
dsWrap.context().getBeanAsync(MybatisSqlSessionFactoryBuilder.class, bean -> {
factoryBuilderPlus = bean;
});
}
/**
* 构建Sql工厂适配器使用属性配置
*/
protected MybatisAdapterPlus(BeanWrap dsWrap, Props dsProps) {
super(dsWrap, dsProps);
this.factoryBuilderPlus = new MybatisSqlSessionFactoryBuilder();
dsWrap.context().getBeanAsync(MybatisSqlSessionFactoryBuilder.class, bean -> {
factoryBuilderPlus = bean;
});
}
/**
* 初始化配置
*/
@Override
protected void initConfiguration(Environment environment) {
//for configuration section
config = new MybatisConfiguration(environment);
Props cfgProps = dsProps.getProp("configuration");
if (cfgProps.size() > 0) {
Utils.injectProperties(config, cfgProps);
}
//for globalConfig section
globalConfig = new GlobalConfig().setDbConfig(new GlobalConfig.DbConfig());
Props globalProps = dsProps.getProp("globalConfig");
if (globalProps.size() > 0) {
//尝试配置注入
Utils.injectProperties(globalConfig, globalProps);
}
GlobalConfigUtils.setGlobalConfig(config, globalConfig);
}
/**
* 获取会话工厂
*/
@Override
public SqlSessionFactory getFactory() {
if (factory == null) {
factory = factoryBuilderPlus.build(getConfiguration());
}
return factory;
}
public SqlSession getSession() {
if (sqlSession == null) {
sqlSession = new SolonSqlSession(getFactory());
}
return sqlSession;
}
@Override
public <T> T getMapper(Class<T> mapperClz) {
Object mapper = mapperCached.get(mapperClz);
if (mapper == null) {
synchronized (mapperClz) {
mapper = mapperCached.get(mapperClz);
if (mapper == null) {
SolonMybatisMapperProxy<T> tMybatisMapperProxy = new SolonMybatisMapperProxy<>(getFactory(), getSession(), mapperClz);
mapper = Proxy.newProxyInstance(
mapperClz.getClassLoader(),
new Class[]{mapperClz},
tMybatisMapperProxy);
mapperCached.put(mapperClz, mapper);
}
}
}
return (T) mapper;
}
/**
* 获取全局配置
*/
public GlobalConfig getGlobalConfig() {
return globalConfig;
}
@Override
public void injectTo(VarHolder varH) {
super.injectTo(varH);
//@Db("db1") SqlSessionFactory factory;
if (GlobalConfig.class.isAssignableFrom(varH.getType())) {
varH.setValue(this.getGlobalConfig());
return;
}
}
}

View File

@ -0,0 +1,209 @@
package com.baomidou.mybatisplus.solon.integration;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.Configuration;
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 org.noear.solon.data.tran.TranUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
public class SolonSqlSession implements SqlSession {
private final SqlSessionFactory sqlSessionFactory;
private final SqlSession sqlSessionProxy;
public SolonSqlSession(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionInterceptor());
}
public SqlSessionFactory getSqlSessionFactory() {
return this.sqlSessionFactory;
}
public SqlSession getSqlSessionProxy() {
return this.sqlSessionProxy;
}
@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 this.getConfiguration().getMapper(type, this);
}
@Override
public void commit() {
throw new UnsupportedOperationException("Manual commit is not allowed over a Solon managed SqlSession");
}
@Override
public void commit(boolean force) {
throw new UnsupportedOperationException("Manual commit is not allowed over a Solon managed SqlSession");
}
@Override
public void rollback() {
throw new UnsupportedOperationException("Manual rollback is not allowed over a Solon managed SqlSession");
}
@Override
public void rollback(boolean force) {
throw new UnsupportedOperationException("Manual rollback is not allowed over a Solon managed SqlSession");
}
@Override
public void close() {
throw new UnsupportedOperationException("Manual close is not allowed over a Solon 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();
}
private class SqlSessionInterceptor implements InvocationHandler {
private SqlSessionInterceptor() {
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object unwrapped;
try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {
Object result = method.invoke(sqlSession, args);
sqlSession.commit(!TranUtils.inTrans());
unwrapped = result;
} catch (Throwable var11) {
unwrapped = ExceptionUtil.unwrapThrowable(var11);
if (unwrapped instanceof RuntimeException) {
throw (RuntimeException) unwrapped;
}
throw (Throwable) unwrapped;
}
return unwrapped;
}
}
}

View File

@ -0,0 +1,39 @@
package com.baomidou.mybatisplus.solon.integration;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
import com.baomidou.mybatisplus.extension.compatible.SolonCompatibleSet;
import com.baomidou.mybatisplus.solon.integration.aot.MybatisPlusRuntimeNativeRegistrar;
import org.noear.solon.aot.RuntimeNativeRegistrar;
import org.noear.solon.core.AppContext;
import org.noear.solon.core.runtime.NativeDetector;
import org.noear.solon.core.util.ClassUtil;
import org.noear.solon.core.util.GenericUtil;
import org.apache.ibatis.solon.integration.MybatisAdapterManager;
import org.noear.solon.core.Plugin;
/**
* @author noear
* @since 1.5
*/
public class XPluginImpl implements Plugin {
@Override
public void start(AppContext context) {
//
// 此插件的 solon.plugin.priority 会大于 mybatis-solon-plugin 的值
//
MybatisAdapterManager.setAdapterFactory(new MybatisAdapterFactoryPlus());
// 注入兼容配置
CompatibleHelper.setCompatibleSet(new SolonCompatibleSet());
// 提供反射处理类
GenericTypeUtils.setGenericTypeResolver((GenericUtil::resolveTypeArguments));
// aot
if (NativeDetector.isAotRuntime() && ClassUtil.hasClass(() -> RuntimeNativeRegistrar.class)) {
context.wrapAndPut(MybatisPlusRuntimeNativeRegistrar.class);
}
}
}

View File

@ -0,0 +1,68 @@
package com.baomidou.mybatisplus.solon.integration.aot;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.interfaces.Compare;
import com.baomidou.mybatisplus.core.conditions.interfaces.Func;
import com.baomidou.mybatisplus.core.conditions.interfaces.Join;
import com.baomidou.mybatisplus.core.conditions.interfaces.Nested;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import org.noear.solon.aot.RuntimeNativeMetadata;
import org.noear.solon.aot.RuntimeNativeRegistrar;
import org.noear.solon.aot.hint.ExecutableMode;
import org.noear.solon.aot.hint.MemberCategory;
import org.noear.solon.core.AppContext;
import java.lang.invoke.SerializedLambda;
/**
* mybatis-plus aot 注册 native 元数据
*
* @author songyinyin
* @since 2.3
*/
public class MybatisPlusRuntimeNativeRegistrar implements RuntimeNativeRegistrar {
@Override
public void register(AppContext context, RuntimeNativeMetadata metadata) {
metadata.registerDefaultConstructor(MybatisXMLLanguageDriver.class);
metadata.registerReflection(MybatisConfiguration.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerAllDeclaredMethod(MybatisConfiguration.class, ExecutableMode.INVOKE);
metadata.registerReflection(AbstractLambdaWrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerJdkProxy(AbstractWrapper.DoSomething.class);
metadata.registerReflection(AbstractWrapper.DoSomething.class);
metadata.registerReflection(AbstractWrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerAllDeclaredMethod(AbstractWrapper.class, ExecutableMode.INVOKE);
metadata.registerReflection(ISqlSegment.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerReflection(Wrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerAllDeclaredMethod(Wrapper.class, ExecutableMode.INVOKE);
metadata.registerReflection(Compare.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerReflection(Func.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerReflection(Join.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerReflection(Nested.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerReflection(LambdaQueryWrapper.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_METHODS,
MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS);
metadata.registerAllDeclaredMethod(LambdaQueryWrapper.class, ExecutableMode.INVOKE);
metadata.registerReflection(Query.class, MemberCategory.DECLARED_FIELDS, MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS);
metadata.registerAllDeclaredMethod(BaseMapper.class, ExecutableMode.INVOKE);
metadata.registerSerialization(SerializedLambda.class);
metadata.registerSerialization(SFunction.class);
}
}

View File

@ -0,0 +1,2 @@
solon.plugin=com.baomidou.mybatisplus.solon.integration.XPluginImpl
solon.plugin.priority=30

View File

@ -0,0 +1,50 @@
package demo;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.zaxxer.hikari.HikariDataSource;
import demo.dso.MetaObjectHandlerImpl;
import demo.dso.MybatisSqlSessionFactoryBuilderImpl;
import okhttp3.Interceptor;
import org.apache.ibatis.solon.annotation.Db;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import javax.sql.DataSource;
@Configuration
public class Config {
@Bean("db1")
public DataSource db1(@Inject("${dataSource.db1}") HikariDataSource hikariDataSource) {
return hikariDataSource;
}
// @Bean
// public Interceptor plusInterceptor() {
// MybatisPlusInterceptor plusInterceptor = new MybatisPlusInterceptor();
// plusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// return plusInterceptor;
// }
@Bean
public void db1_ext(@Db("db1") GlobalConfig globalConfig) {
MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl();
globalConfig.setMetaObjectHandler(metaObjectHandler);
}
@Bean
public void db1_ext2(@Db("db1") MybatisConfiguration config){
config.getTypeHandlerRegistry().register("xxx");
config.setDefaultEnumTypeHandler(null);
}
@Bean
public MybatisSqlSessionFactoryBuilder factoryBuilderNew(){
return new MybatisSqlSessionFactoryBuilderImpl();
}
}

View File

@ -0,0 +1,22 @@
package demo;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import demo.dso.service.UserService;
import demo.model.User;
import org.noear.solon.Solon;
import java.util.List;
/**
* @author noear 2021/7/12 created
*/
public class DemoApp {
public static void main(String[] args) {
Solon.start(DemoApp.class, args);
//test
UserService userService = Solon.context().getBean(UserService.class);
Assert.notNull(userService.getUserList(), "查询结果异常");
}
}

View File

@ -0,0 +1,21 @@
package demo.controller;
import demo.dso.service.UserService;
import demo.model.User;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import java.util.List;
@Controller
public class IndexController {
@Inject
UserService userService;
@Mapping("/")
public List<User> index() {
return userService.getUserList();
}
}

View File

@ -0,0 +1,19 @@
package demo.dso;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
/**
* @author noear 2022/4/17 created
*/
public class MetaObjectHandlerImpl implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
}
@Override
public void updateFill(MetaObject metaObject) {
}
}

View File

@ -0,0 +1,9 @@
package demo.dso;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
/**
* @author noear 2021/10/20 created
*/
public class MybatisSqlSessionFactoryBuilderImpl extends MybatisSqlSessionFactoryBuilder {
}

View File

@ -0,0 +1,10 @@
package demo.dso.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import demo.model.User;
/**
* @author
*/
public interface UserMapper extends BaseMapper<User> {
}

View File

@ -0,0 +1,24 @@
package demo.dso.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import demo.dso.mapper.UserMapper;
import demo.model.User;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import java.util.List;
/**
* @author noear 2021/9/9 created
*/
@Component
public class UserService {
@Inject
UserMapper userMapper;
public List<User> getUserList() {
assert userMapper != null;
return userMapper.selectList(new QueryWrapper<>());
}
}

View File

@ -0,0 +1,31 @@
package demo.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* @author iYarnFog
*/
@TableName(value = "users")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String uuid;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
}

View File

@ -0,0 +1,27 @@
package features;
import com.baomidou.mybatisplus.core.mapper.Mapper;
import demo.dso.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.noear.solon.core.util.GenericUtil;
import java.util.Arrays;
import java.util.Map;
public class IGenericTypeResolverImplTest {
@Test
public void resolveTypeArguments() {
System.out.println(Arrays.toString(GenericUtil.resolveTypeArguments(DemoImpl.class, Map.class)));
System.out.println(Arrays.toString(GenericUtil.resolveTypeArguments(DemoImpl.class, Demo.class)));
System.out.println(Arrays.toString(GenericUtil.resolveTypeArguments(UserMapper.class, Mapper.class)));
}
private interface Demo<T> {}
private abstract static class DemoImpl implements Map<Integer, String>, IGenericTypeResolverImplTest.Demo<Double> {
}
}

View File

@ -0,0 +1,25 @@
server:
port: 6040
# 配置数据源
dataSource:
db1:
# 与数据库名可用保持一致
schema: test
jdbcUrl: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: 1234
mybatis:
db1:
mappers:
- "demo.dso.mapper.*"
configuration:
cacheEnabled: false
mapUnderscoreToCamelCase: true
globalConfig:
banner: false
metaObjectHandler: "demo.dso.MetaObjectHandlerImpl"
dbConfig:
logicDeleteField: "deleted"

View File

@ -0,0 +1,29 @@
apply plugin: 'kotlin'
compileKotlin{
kotlinOptions.jvmTarget = "1.8"
}
dependencies {
api project(":mybatis-plus-extension")
implementation "${lib."mybatis-spring"}"
implementation "${lib."kotlin-stdlib-jdk8"}"
implementation "${lib."kotlin-reflect"}"
implementation "${lib."spring-context-support"}"
implementation "${lib."spring-jdbc"}"
implementation "${lib."slf4j-api"}"
implementation "${lib."p6spy"}"
implementation "${lib."jackson"}"
implementation "${lib."fastjson"}"
implementation "${lib."gson"}"
implementation "${lib['mybatis-thymeleaf']}"
implementation "${lib.'mybatis-velocity'}"
implementation "${lib.'mybatis-freemarker'}"
implementation "de.ruedigermoeller:fst:3.0.4-jdk17"
implementation "com.github.ben-manes.caffeine:caffeine:2.9.3"
testImplementation "io.github.classgraph:classgraph:4.8.176"
testImplementation "${lib.h2}"
testImplementation "${lib.mysql}"
testImplementation "${lib.'logback-classic'}"
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.activerecord;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
/**
* ActiveRecord 模式 CRUD
* <p>
* 必须存在对应的原始mapper并继承baseMapper并且可以使用的前提下
* 才能使用此 AR 模式 !!!
* </p>
*
* @param <T>
* @author hubin
* @since 2016-11-06
*/
public abstract class Model<T extends Model<?>> extends AbstractModel<T> {
/**
* 执行 SQL
*/
public SqlRunner sql() {
return new SqlRunner(this.entityClass);
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.compatible;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import lombok.SneakyThrows;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionHolder;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.io.InputStream;
import java.util.function.Consumer;
/**
* spring 兼容方法集接口实现类
*/
public class SpringCompatibleSet implements CompatibleSet {
@Override
public SqlSession getSqlSession(SqlSessionFactory sessionFactory) {
return SqlSessionUtils.getSqlSession(sessionFactory);
}
@Override
public void closeSqlSession(SqlSession sqlSession, SqlSessionFactory sqlSessionFactory) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
@SneakyThrows
@Override
public boolean executeBatch(SqlSessionFactory sqlSessionFactory, Log log, Consumer<SqlSession> consumer) {
SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
if (sqlSessionHolder != null) {
SqlSession sqlSession = sqlSessionHolder.getSqlSession();
//原生无法支持执行器切换当存在批量操作时会嵌套两个session的优先commit上一个session
//按道理来说这里的值应该一直为false
sqlSession.commit(!transaction);
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
if (!transaction) {
log.warn("SqlSession [" + sqlSession + "] Transaction not enabled");
}
try {
consumer.accept(sqlSession);
//非事务情况下强制commit
sqlSession.commit(!transaction);
return true;
} catch (Throwable t) {
sqlSession.rollback();
Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
if (unwrapped instanceof PersistenceException) {
MyBatisExceptionTranslator myBatisExceptionTranslator
= new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
Throwable throwable = myBatisExceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (throwable != null) {
throw throwable;
}
}
throw ExceptionUtils.mpe(unwrapped);
} finally {
sqlSession.close();
}
}
@Override
public InputStream getInputStream(String path) throws Exception {
return new ClassPathResource(path).getInputStream();
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.repository;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.binding.MapperMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
/**
* IService 实现类 泛型M mapper 对象T 是实体
*
* @author hubin
* @since 2018-06-23
*/
public abstract class CrudRepository<M extends BaseMapper<T>, T> extends AbstractRepository<M, T> {
@Autowired
protected M baseMapper;
@Override
public M getBaseMapper() {
Assert.notNull(this.baseMapper, "baseMapper can not be null");
return this.baseMapper;
}
/**
* 批量插入
*
* @param entityList ignore
* @param batchSize ignore
* @return ignore
*/
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
}
/**
* 获取mapperStatementId
*
* @param sqlMethod 方法名
* @return 命名id
* @since 3.4.0
*/
protected String getSqlStatement(SqlMethod sqlMethod) {
return SqlHelper.getSqlStatement(this.getMapperClass(), sqlMethod);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.getEntityClass());
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
return SqlHelper.saveOrUpdateBatch(getSqlSessionFactory(), this.getMapperClass(), this.log, entityList, batchSize, (sqlSession, entity) -> {
Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
return StringUtils.checkValNull(idVal)
|| CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
}, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
});
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(sqlStatement, param);
});
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.service;
import com.baomidou.mybatisplus.extension.repository.IRepository;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
/**
* 顶级 Service
* <p>
*
* </p>
*
* @author hubin
* @since 2018-06-23
*/
public interface IService<T> extends IRepository<T> {
/**
* 插入批量
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveBatch(Collection<T> entityList) {
return saveBatch(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 批量修改插入
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 批量删除(jdbc批量提交)
*
* @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)
* @return 删除结果
* @since 3.5.0
*/
@Transactional(rollbackFor = Exception.class)
default boolean removeBatchByIds(Collection<?> list) {
return removeByIds(list);
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baomidou.mybatisplus.extension.service.impl;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* IService 实现类 泛型M mapper 对象T 是实体
*
* @author hubin
* @since 2018-06-23
*/
public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T> implements IService<T> {
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 通用 service 实现
*
* @author hubin
* @since 2018-06-08
*/
package com.baomidou.mybatisplus.extension.service.impl;

View File

@ -14,6 +14,9 @@
* limitations under the License.
*/
/**
* Spring相关类
* 通用 Service 接口
*
* @author hubin
* @since 2018-06-08
*/
package com.baomidou.mybatisplus.extension.spring;
package com.baomidou.mybatisplus.extension.service;

View File

@ -15,11 +15,7 @@
*/
package com.baomidou.mybatisplus.extension.spring;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisPlusVersion;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
import com.baomidou.mybatisplus.core.MybatisXMLConfigBuilder;
import com.baomidou.mybatisplus.core.MybatisXMLMapperBuilder;
import com.baomidou.mybatisplus.core.*;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
@ -61,13 +57,7 @@ import javax.sql.DataSource;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.*;
import java.util.function.IntFunction;
import java.util.stream.Stream;

View File

@ -10,7 +10,6 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.assertj.core.api.Assertions.assertThat;
/**

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;

View File

@ -16,7 +16,6 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static com.baomidou.mybatisplus.core.enums.SqlMethod.UPSERT_ONE;
import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -13,8 +13,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author miemie
* @since 2021-03-16

View File

@ -1,16 +1,15 @@
package com.baomidou.mybatisplus.test.toolkit;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.baomidou.mybatisplus.test.BaseDbTest;
import com.baomidou.mybatisplus.test.rewrite.Entity;
import com.baomidou.mybatisplus.test.rewrite.EntityMapper;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
/**
* SqlHelper 工具类测试

View File

@ -21,6 +21,8 @@ include 'mybatis-plus-annotation'
include 'mybatis-plus-extension'
include 'mybatis-plus-generator'
include 'mybatis-plus-bom'
include 'mybatis-plus-spring'
include 'mybatis-plus-solon-plugin'
include 'spring-boot-starter'
include ':spring-boot-starter:mybatis-plus-boot-starter'
include ':spring-boot-starter:mybatis-plus-boot-starter-test'

View File

@ -1,4 +1,6 @@
dependencies {
api project(":mybatis-plus-spring")
implementation project(":mybatis-plus")
implementation "${lib."mybatis-spring"}"
implementation "org.springframework.boot:spring-boot-autoconfigure:${springBootVersion}"

View File

@ -24,6 +24,8 @@ import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.compatible.CompatibleHelper;
import com.baomidou.mybatisplus.extension.compatible.SpringCompatibleSet;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.mapping.DatabaseIdProvider;
@ -148,6 +150,9 @@ public class MybatisPlusAutoConfiguration implements InitializingBean {
this.sqlSessionFactoryBeanCustomizers = sqlSessionFactoryBeanCustomizers.getIfAvailable();
this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();
this.applicationContext = applicationContext;
// 注入兼容配置
CompatibleHelper.setCompatibleSet(new SpringCompatibleSet());
}
@Override