Skip to content

Commit 810f0c6

Browse files
committed
# 抛弃 改造 MybatisPlus 源码方式 ,支持JPA 注解,在EL 中 进行MybatisPlus 适配
1 parent b8b23c3 commit 810f0c6

29 files changed

+4140
-17
lines changed

eladmin-common/src/main/java/com/baomidou/mybatisplus/core/metadata/ElTableInfoHelper.java

Lines changed: 556 additions & 0 deletions
Large diffs are not rendered by default.

eladmin-common/src/main/java/me/zhengjie/base/BaseDao.java renamed to eladmin-common/src/main/java/me/zhengjie/base/mybatis/BaseDao.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package me.zhengjie.base;
1+
package me.zhengjie.base.mybatis;
22

33
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
44
import com.baomidou.mybatisplus.extension.service.IService;
@@ -20,7 +20,7 @@
2020
public class BaseDao<I extends IService<T>, J extends JpaRepository<T, ID>, T, ID extends Serializable> {
2121
protected I mpService;
2222
protected J jpaRepository;
23-
@Value("${db.type.switch:true}")
23+
@Value("${db.type.switch:false}")
2424
protected boolean dbSwitch;
2525

2626
public BaseDao(I mpService, J jpaRepository) {
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
/*
2+
* Copyright (c) 2011-2020, baomidou (jobob@qq.com).
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package me.zhengjie.base.mybatis;
17+
18+
import com.baomidou.mybatisplus.core.conditions.Wrapper;
19+
import com.baomidou.mybatisplus.core.enums.SqlMethod;
20+
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
21+
import com.baomidou.mybatisplus.core.metadata.ElTableInfoHelper;
22+
import com.baomidou.mybatisplus.core.metadata.TableInfo;
23+
import com.baomidou.mybatisplus.core.toolkit.*;
24+
import com.baomidou.mybatisplus.extension.service.IService;
25+
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
26+
import org.apache.ibatis.binding.MapperMethod;
27+
import org.apache.ibatis.logging.Log;
28+
import org.apache.ibatis.logging.LogFactory;
29+
import org.apache.ibatis.reflection.ExceptionUtil;
30+
import org.apache.ibatis.session.ExecutorType;
31+
import org.apache.ibatis.session.SqlSession;
32+
import org.apache.ibatis.session.SqlSessionFactory;
33+
import org.mybatis.spring.MyBatisExceptionTranslator;
34+
import org.mybatis.spring.SqlSessionHolder;
35+
import org.mybatis.spring.SqlSessionUtils;
36+
import org.springframework.beans.factory.annotation.Autowired;
37+
import org.springframework.transaction.annotation.Transactional;
38+
import org.springframework.transaction.support.TransactionSynchronizationManager;
39+
40+
import java.io.Serializable;
41+
import java.util.Collection;
42+
import java.util.Map;
43+
import java.util.Objects;
44+
import java.util.function.BiConsumer;
45+
import java.util.function.Consumer;
46+
import java.util.function.Function;
47+
48+
/**
49+
* IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
50+
*
51+
* @author hubin
52+
* @since 2018-06-23
53+
*/
54+
@SuppressWarnings("unchecked")
55+
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
56+
57+
protected Log log = LogFactory.getLog(getClass());
58+
59+
@Autowired
60+
protected M baseMapper;
61+
62+
@Override
63+
public M getBaseMapper() {
64+
return baseMapper;
65+
}
66+
67+
protected Class<?> entityClass = currentModelClass();
68+
69+
/**
70+
* 判断数据库操作是否成功
71+
*
72+
* @param result 数据库操作返回影响条数
73+
* @return boolean
74+
* @deprecated 3.3.1
75+
*/
76+
@Deprecated
77+
protected boolean retBool(Integer result) {
78+
return SqlHelper.retBool(result);
79+
}
80+
81+
protected Class<T> currentModelClass() {
82+
return (Class<T>) ReflectionKit.getSuperClassGenericType(getClass(), 1);
83+
}
84+
85+
/**
86+
* 批量操作 SqlSession
87+
*
88+
* @deprecated 3.3.0
89+
*/
90+
@Deprecated
91+
protected SqlSession sqlSessionBatch() {
92+
return SqlHelper.sqlSessionBatch(entityClass);
93+
}
94+
95+
/**
96+
* 释放sqlSession
97+
*
98+
* @param sqlSession session
99+
* @deprecated 3.3.0
100+
*/
101+
@Deprecated
102+
protected void closeSqlSession(SqlSession sqlSession) {
103+
SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(entityClass));
104+
}
105+
106+
/**
107+
* 获取 SqlStatement
108+
*
109+
* @param sqlMethod ignore
110+
* @return ignore
111+
*/
112+
protected String sqlStatement(SqlMethod sqlMethod) {
113+
return SqlHelper.table(entityClass).getSqlStatement(sqlMethod.getMethod());
114+
}
115+
116+
/**
117+
* 批量插入
118+
*
119+
* @param entityList ignore
120+
* @param batchSize ignore
121+
* @return ignore
122+
*/
123+
@Transactional(rollbackFor = Exception.class)
124+
@Override
125+
public boolean saveBatch(Collection<T> entityList, int batchSize) {
126+
String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
127+
return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
128+
}
129+
130+
/**
131+
* TableId 注解存在更新记录,否插入一条记录
132+
*
133+
* @param entity 实体对象
134+
* @return boolean
135+
*/
136+
@Transactional(rollbackFor = Exception.class)
137+
@Override
138+
public boolean saveOrUpdate(T entity) {
139+
if (null != entity) {
140+
Class<?> cls = entity.getClass();
141+
TableInfo tableInfo = ElTableInfoHelper.getTableInfo(cls);
142+
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
143+
String keyProperty = tableInfo.getKeyProperty();
144+
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
145+
Object idVal = ReflectionKit.getFieldValue(entity, tableInfo.getKeyProperty());
146+
return StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal)) ? save(entity) : updateById(entity);
147+
}
148+
return false;
149+
}
150+
151+
@Transactional(rollbackFor = Exception.class)
152+
@Override
153+
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
154+
TableInfo tableInfo = ElTableInfoHelper.getTableInfo(entityClass);
155+
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
156+
String keyProperty = tableInfo.getKeyProperty();
157+
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
158+
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
159+
Object idVal = ReflectionKit.getFieldValue(entity, keyProperty);
160+
if (StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal))) {
161+
sqlSession.insert(tableInfo.getSqlStatement(SqlMethod.INSERT_ONE.getMethod()), entity);
162+
} else {
163+
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
164+
param.put(Constants.ENTITY, entity);
165+
sqlSession.update(tableInfo.getSqlStatement(SqlMethod.UPDATE_BY_ID.getMethod()), param);
166+
}
167+
});
168+
}
169+
170+
@Transactional(rollbackFor = Exception.class)
171+
@Override
172+
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
173+
String sqlStatement = sqlStatement(SqlMethod.UPDATE_BY_ID);
174+
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
175+
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
176+
param.put(Constants.ENTITY, entity);
177+
sqlSession.update(sqlStatement, param);
178+
});
179+
}
180+
181+
@Override
182+
public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
183+
if (throwEx) {
184+
return baseMapper.selectOne(queryWrapper);
185+
}
186+
return SqlHelper.getObject(log, baseMapper.selectList(queryWrapper));
187+
}
188+
189+
@Override
190+
public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
191+
return SqlHelper.getObject(log, baseMapper.selectMaps(queryWrapper));
192+
}
193+
194+
@Override
195+
public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
196+
return SqlHelper.getObject(log, listObjs(queryWrapper, mapper));
197+
}
198+
199+
/**
200+
* 执行批量操作
201+
*
202+
* @param consumer consumer
203+
* @since 3.3.0
204+
* @deprecated 3.3.1 后面我打算移除掉 {@link #executeBatch(Collection, int, BiConsumer)} }.
205+
*/
206+
@Deprecated
207+
protected boolean executeBatch(Consumer<SqlSession> consumer) {
208+
SqlSessionFactory sqlSessionFactory = SqlHelper.sqlSessionFactory(entityClass);
209+
SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
210+
boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
211+
if (sqlSessionHolder != null) {
212+
SqlSession sqlSession = sqlSessionHolder.getSqlSession();
213+
//原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session
214+
//按道理来说,这里的值应该一直为false。
215+
sqlSession.commit(!transaction);
216+
}
217+
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
218+
if (!transaction) {
219+
log.warn("SqlSession [" + sqlSession + "] was not registered for synchronization because DataSource is not transactional");
220+
}
221+
try {
222+
consumer.accept(sqlSession);
223+
//非事物情况下,强制commit。
224+
sqlSession.commit(!transaction);
225+
return true;
226+
} catch (Throwable t) {
227+
sqlSession.rollback();
228+
Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
229+
if (unwrapped instanceof RuntimeException) {
230+
MyBatisExceptionTranslator myBatisExceptionTranslator
231+
= new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
232+
throw Objects.requireNonNull(myBatisExceptionTranslator.translateExceptionIfPossible((RuntimeException) unwrapped));
233+
}
234+
throw ExceptionUtils.mpe(unwrapped);
235+
} finally {
236+
sqlSession.close();
237+
}
238+
}
239+
240+
/**
241+
* 执行批量操作
242+
*
243+
* @param list 数据集合
244+
* @param batchSize 批量大小
245+
* @param consumer 执行方法
246+
* @param <E> 泛型
247+
* @return 操作结果
248+
* @since 3.3.1
249+
*/
250+
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
251+
Assert.isFalse(batchSize < 1, "batchSize must not be less than one");
252+
return !CollectionUtils.isEmpty(list) && executeBatch(sqlSession -> {
253+
int size = list.size();
254+
int i = 1;
255+
for (E element : list) {
256+
consumer.accept(sqlSession, element);
257+
if ((i % batchSize == 0) || i == size) {
258+
sqlSession.flushStatements();
259+
}
260+
i++;
261+
}
262+
});
263+
}
264+
265+
/**
266+
* 执行批量操作(默认批次提交数量{@link IService#DEFAULT_BATCH_SIZE})
267+
*
268+
* @param list 数据集合
269+
* @param consumer 执行方法
270+
* @param <E> 泛型
271+
* @return 操作结果
272+
* @since 3.3.1
273+
*/
274+
protected <E> boolean executeBatch(Collection<E> list, BiConsumer<SqlSession, E> consumer) {
275+
return executeBatch(list, DEFAULT_BATCH_SIZE, consumer);
276+
}
277+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2019-2020
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package me.zhengjie.mybatis;
17+
18+
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
19+
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
20+
import com.baomidou.mybatisplus.core.metadata.ElTableInfoHelper;
21+
import com.baomidou.mybatisplus.core.metadata.TableInfo;
22+
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
23+
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
24+
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
25+
import org.apache.ibatis.builder.MapperBuilderAssistant;
26+
import org.apache.ibatis.logging.Log;
27+
import org.apache.ibatis.logging.LogFactory;
28+
29+
import java.lang.reflect.ParameterizedType;
30+
import java.lang.reflect.Type;
31+
import java.lang.reflect.TypeVariable;
32+
import java.lang.reflect.WildcardType;
33+
import java.util.List;
34+
import java.util.Set;
35+
36+
/**
37+
* SQL 自动注入器
38+
*
39+
* @author hubin
40+
* @author liaojinlong
41+
* @since 2020/6/29 18:14
42+
*/
43+
public abstract class AbstractSqlInjector implements ISqlInjector {
44+
45+
private static final Log logger = LogFactory.getLog(AbstractSqlInjector.class);
46+
47+
@Override
48+
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
49+
Class<?> modelClass = extractModelClass(mapperClass);
50+
if (modelClass != null) {
51+
String className = mapperClass.toString();
52+
Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
53+
if (!mapperRegistryCache.contains(className)) {
54+
List<AbstractMethod> methodList = this.getMethodList(mapperClass);
55+
if (CollectionUtils.isNotEmpty(methodList)) {
56+
TableInfo tableInfo = ElTableInfoHelper.initTableInfo(builderAssistant, modelClass);
57+
// 循环注入自定义方法
58+
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
59+
} else {
60+
logger.debug(mapperClass.toString() + ", No effective injection method was found.");
61+
}
62+
mapperRegistryCache.add(className);
63+
}
64+
}
65+
}
66+
67+
/**
68+
* <p>
69+
* 获取 注入的方法
70+
* </p>
71+
*
72+
* @param mapperClass 当前mapper
73+
* @return 注入的方法集合
74+
* @since 3.1.2 add mapperClass
75+
*/
76+
public abstract List<AbstractMethod> getMethodList(Class<?> mapperClass);
77+
78+
/**
79+
* 提取泛型模型,多泛型的时候请将泛型T放在第一位
80+
*
81+
* @param mapperClass mapper 接口
82+
* @return mapper 泛型
83+
*/
84+
protected Class<?> extractModelClass(Class<?> mapperClass) {
85+
Type[] types = mapperClass.getGenericInterfaces();
86+
ParameterizedType target = null;
87+
for (Type type : types) {
88+
if (type instanceof ParameterizedType) {
89+
Type[] typeArray = ((ParameterizedType) type).getActualTypeArguments();
90+
if (ArrayUtils.isNotEmpty(typeArray)) {
91+
for (Type t : typeArray) {
92+
if (t instanceof TypeVariable || t instanceof WildcardType) {
93+
break;
94+
} else {
95+
target = (ParameterizedType) type;
96+
break;
97+
}
98+
}
99+
}
100+
break;
101+
}
102+
}
103+
return target == null ? null : (Class<?>) target.getActualTypeArguments()[0];
104+
}
105+
}

0 commit comments

Comments
 (0)