新增dao、mysql方言部分封装、测试代码

This commit is contained in:
aoshiguchen
2022-06-28 17:05:14 +08:00
parent 58cd2e4a16
commit 13b5614fe2
16 changed files with 1158 additions and 107 deletions
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
*
* @author: aoshiguchen
* @date: 2022/6/28
*/
@Getter
@AllArgsConstructor
public enum DBType {
MYSQL(1, "mysql"),
SQL_SERVER(2, "sqserver"),
ORACLE(3, "oracle"),
SQL_LITE(4, "sqllite"),
MONGO(5, "mongodb");
private static final Map<Integer, DBType> typeMap = Stream.of(DBType.values()).collect(Collectors.toMap(DBType::getType, Function.identity()));
private static final Map<String, DBType> nameMap = Stream.of(DBType.values()).collect(Collectors.toMap(DBType::getName, Function.identity()));
private Integer type;
private String name;
public static DBType byType(Integer type) {
return typeMap.get(type);
}
public static DBType byName(String name) {
return nameMap.get(name);
}
}
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
import java.io.Serializable;
import java.util.List;
/**
* @author: aoshiguchen
* @date: 2022/6/28
*/
public interface Dao<T> {
//==============================================新增=====================
/**
* 新增单条记录
* @param po
* @return
*/
T add(T po);
//==============================================修改=====================
/**
* 更新单条记录
* @param po
* @return
*/
int updateById(T po);
/**
* 更新单条记录
* @param po
* @param field
* @return
*/
int updateById(T po, String ...field);
//==============================================删除=====================
/**
* 根据id删除
* @param id
* @return
*/
int deleteById(Serializable id);
int delete(T po, String ...field);
int delete();
//==============================================查询=====================
Long count();
Long count(T po, String ...field);
T findOneById(Serializable id);
T findOne(T po, String ...field);
List<T> find();
List<T> find(T po, String ...field);
List<T> findPage(int beginNo, int pageSize);
List<T> findPage(T po,int beginNo, int pageSize, String ...field);
}
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
/**
*
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class DaoFactory {
}
@@ -0,0 +1,232 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
import com.google.common.collect.Sets;
import fun.asgc.neutrino.core.cache.Cache;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.template.DataSourceHolder;
import fun.asgc.neutrino.core.db.template.DbCache;
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
import fun.asgc.neutrino.core.db.template.SqlAndParams;
import fun.asgc.neutrino.core.util.Assert;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.ReflectUtil;
import javax.sql.DataSource;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
/**
* TODO 暂时先实现一部分,需要放下来思考更好的方式
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class DefaultDaoImpl<T> implements Dao<T> {
/**
* 数据源持有者
*/
private DataSourceHolder dataSourceHolder;
/**
* jdbc操作工具
*/
private JdbcTemplate jdbcTemplate;
/**
* 实体类
*/
private Class<T> entryClass;
/**
* sql方言
*/
private SqlDialect sqlDialect;
/**
* id字段
*/
private Field idField;
/**
* id列名
*/
private String idColumnName;
public DefaultDaoImpl(DataSource dataSource, DBType dbType, Class<T> entryClass) {
this(new DataSourceHolder(dataSource, dbType), entryClass);
}
public DefaultDaoImpl(DataSourceHolder dataSourceHolder, Class<T> entryClass) {
Assert.notNull(dataSourceHolder, "数据源持有者不能为空!");
Assert.notNull(dataSourceHolder.getDbType(), "数据库类型不能为空!");
Assert.notNull(entryClass, "实体类不能为空!");
this.dataSourceHolder = dataSourceHolder;
this.jdbcTemplate = new JdbcTemplate(this.dataSourceHolder);
this.entryClass = entryClass;
this.sqlDialect = SqlDialectFactory.getSqlDialect(this.dataSourceHolder.getDbType());
this.idField = getIdField(this.entryClass);
Assert.notNull(idField, "实体类必须存在主键");
this.idColumnName = DbCache.getColumnNameByField(idField);
}
@Override
public T add(T po) {
SqlAndParams sqlAndParams = this.sqlDialect.add(po);
jdbcTemplate.update(sqlAndParams.getSql());
Serializable idValue = getIdValue(po);
if (null != idValue) {
return findOneById(idValue);
}
return null;
}
@Override
public int delete(T po, String... field) {
return 0;
}
@Override
public int delete() {
return 0;
}
@Override
public Long count() {
SqlAndParams sqlAndParams = this.sqlDialect.count(entryClass, null);
return jdbcTemplate.queryForLong(sqlAndParams.getSql(), sqlAndParams.getParamArray());
}
@Override
public Long count(T po, String... field) {
Set<String> filter = Sets.newHashSet(field);
Cache<Field, String> fieldCache = DbCache.getFieldCache(entryClass);
SqlAndParams sqlAndParams = this.sqlDialect.count(entryClass, new LinkedHashMap<String, Object>(){
{
for (Field item : fieldCache.keySet()) {
if (!filter.isEmpty() && !filter.contains(item.getName())) {
continue;
}
this.put(fieldCache.get(item), ReflectUtil.getFieldValue(item, po));
}
}
});
return jdbcTemplate.queryForLong(sqlAndParams.getSql(), sqlAndParams.getParamArray());
}
@Override
public T findOneById(Serializable id) {
SqlAndParams sqlAndParams = this.sqlDialect.find(entryClass, new LinkedHashMap<String, Object>(){
{
this.put(idColumnName, id);
}
});
return jdbcTemplate.query(entryClass, sqlAndParams);
}
@Override
public T findOne(T po, String... field) {
Set<String> filter = Sets.newHashSet(field);
Cache<Field, String> fieldCache = DbCache.getFieldCache(entryClass);
SqlAndParams sqlAndParams = this.sqlDialect.find(entryClass, new LinkedHashMap<String, Object>(){
{
for (Field item : fieldCache.keySet()) {
if (!filter.isEmpty() && !filter.contains(item.getName())) {
continue;
}
this.put(fieldCache.get(item), ReflectUtil.getFieldValue(item, po));
}
}
});
return jdbcTemplate.query(entryClass, sqlAndParams);
}
@Override
public List<T> find() {
SqlAndParams sqlAndParams = this.sqlDialect.find(entryClass, null);
return jdbcTemplate.queryForList(entryClass, sqlAndParams);
}
@Override
public List<T> find(T po, String... field) {
Set<String> filter = Sets.newHashSet(field);
Cache<Field, String> fieldCache = DbCache.getFieldCache(entryClass);
SqlAndParams sqlAndParams = this.sqlDialect.find(entryClass, new LinkedHashMap<String, Object>(){
{
for (Field item : fieldCache.keySet()) {
if (!filter.isEmpty() && !filter.contains(item.getName())) {
continue;
}
this.put(fieldCache.get(item), ReflectUtil.getFieldValue(item, po));
}
}
});
return jdbcTemplate.queryForList(entryClass, sqlAndParams);
}
@Override
public List<T> findPage(int beginNo, int pageSize) {
return null;
}
@Override
public int updateById(T po) {
return 0;
}
@Override
public int updateById(T po, String... field) {
return 0;
}
@Override
public int deleteById(Serializable id) {
return 0;
}
@Override
public List<T> findPage(T po, int beginNo, int pageSize, String... field) {
return null;
}
private <V> V getIdValue(Object obj) {
if (null == obj) {
return null;
}
return (V)ReflectUtil.getFieldValue(idField, obj);
}
private static Field getIdField(Class<?> clazz) {
List<Field> fieldList = DbCache.getFieldList(clazz);
if (CollectionUtil.isEmpty(fieldList)) {
return null;
}
Field res = null;
for (Field field : fieldList) {
if (field.isAnnotationPresent(Id.class)) {
return field;
}
if (field.getName().equals("id")) {
res = field;
}
}
return res;
}
}
@@ -19,10 +19,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dialect;
package fun.asgc.neutrino.core.db.dao;
import java.util.Map;
import java.util.Set;
import fun.asgc.neutrino.core.db.template.SqlAndParams;
import java.util.LinkedHashMap;
/**
* sql方言用于屏蔽各种不同的数据库的sql差异
@@ -31,81 +32,23 @@ import java.util.Set;
*/
public interface SqlDialect {
/**
* 获取记录
* 新增单条记录
* @param obj
* @return
*/
String getRecordCount();
SqlAndParams add(Object obj);
/**
* 查询所有数据
* 查询单条记录
* @return
*/
String findAll();
SqlAndParams find(Class<?> clazz, LinkedHashMap<String, Object> params);
/**
* 根据id查询单条数
* @param id
* @return
*/
String findById(String id);
/**
* 查询
* @param filterField
* 查询数据条数
* @param clazz
* @param params
* @return
*/
String find(Set<String> filterField, Map<String,Object> params);
/**
* 根据id删除
* @param id
* @return
*/
String deleteById(String id);
/**
* 删除
* @param filterField
* @param params
* @return
*/
String delete(Set<String> filterField,Map<String,Object> params);
/**
* 删除所有数据
* @return
*/
String deleteAll();
/**
* 更新
* @param filterField
* @param params
* @return
*/
String update(Set<String> filterField,Map<String,Object> params);
/**
* 新增
* @param filterField
* @param params
* @return
*/
String create(Set<String> filterField,Map<String,Object> params);
/**
* 分页查询
* @return
*/
String findPage();
/**
* 分页查询
* @param filterField
* @param params
* @return
*/
String findPage(Set<String> filterField,Map<String,Object> params);
SqlAndParams count(Class<?> clazz, LinkedHashMap<String, Object> params);
}
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
import fun.asgc.neutrino.core.util.Assert;
/**
* sql方言工厂 TODO 暂时只支持mysql
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class SqlDialectFactory {
private static final SqlDialect mysql = new SqlDialectForMysql();
public static SqlDialect getSqlDialect(DBType dbType) {
Assert.notNull(dbType, "数据库类型不能为空!");
switch (dbType) {
case MYSQL: return mysql;
default: {
throw new RuntimeException("不支持的数据库类型!");
}
}
}
}
@@ -0,0 +1,245 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
import fun.asgc.neutrino.core.cache.Cache;
import fun.asgc.neutrino.core.db.template.DbCache;
import fun.asgc.neutrino.core.db.template.SqlAndParams;
import fun.asgc.neutrino.core.util.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
*
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class SqlDialectForMysql implements SqlDialect {
private static final String TEMPLATE_FIND = "select * from `${tableName}` ${where}";
private static final String TEMPLATE_COUNT = "select count(*) from `${tableName}` ${where}";
private static final String TEMPLATE_LIMIT = "limit ${offset},${size}";
private static final String TEMPLATE_INSERT = "insert into `${tableName}`(${columns}) values ${values}";
private static final String TEMPLATE_UPDATE = "update `${tableName}` ${set} ${where}`";
private static final String TEMPLATE_DELETE = "delete from `${tableName}` ${where}";
@Override
public SqlAndParams add(Object obj) {
LinkedHashMap<String, Object> params = getParams(obj);
Set<String> filterColumns = params.keySet();
String sql = templateProcess(TEMPLATE_INSERT, new HashMap<String, String>(){
{
this.put("tableName", getTableName(obj));
this.put("columns", buildSqlColumns(filterColumns));
this.put("values", getSqlValue(filterColumns, params));
}
});
return new SqlAndParams(sql);
}
@Override
public SqlAndParams find(Class<?> clazz, LinkedHashMap<String, Object> params) {
String sql = templateProcess(TEMPLATE_FIND, new HashMap<String, String>(){
{
this.put("tableName", getTableName(clazz));
this.put("where", buildSqlWhere(null, params));
}
});
return new SqlAndParams(sql, params);
}
@Override
public SqlAndParams count(Class<?> clazz, LinkedHashMap<String, Object> params) {
String sql = templateProcess(TEMPLATE_COUNT, new HashMap<String, String>(){
{
this.put("tableName", getTableName(clazz));
this.put("where", buildSqlWhere(null, params));
}
});
return new SqlAndParams(sql, params);
}
/**
* 获取表名
* @param obj
* @return
*/
private static String getTableName(Object obj) {
Assert.notNull(obj, "对象不能为空!");
return DbCache.toTableName(obj.getClass());
}
/**
* 获取表名
* @param clazz
* @return
*/
private static String getTableName(Class clazz) {
Assert.notNull(clazz, "类不能为空!");
return DbCache.toTableName(clazz);
}
/**
* 获取参数
* @param obj
* @return
*/
private static LinkedHashMap<String, Object> getParams(Object obj) {
return getParams(obj, null);
}
/**
* 获取参数
* @param obj
* @return
*/
private static LinkedHashMap<String, Object> getParams(Object obj, Set<String> excludeFieldName) {
Assert.notNull(obj, "对象不能为空!");
Cache<Field, String> cache = DbCache.getFieldCache(obj.getClass());
LinkedHashMap<String, Object> params = new LinkedHashMap<>();
if (null == cache || cache.isEmpty()) {
return params;
}
Set<String> tmp = new HashSet<>();
for (Field field : cache.keySet()) {
String column = cache.get(field);
if (tmp.contains(column)) {
continue;
}
if (CollectionUtil.notEmpty(excludeFieldName) && excludeFieldName.contains(field.getName())) {
continue;
}
tmp.add(column);
Object value = ReflectUtil.getFieldValue(field, obj);
params.put(column, value);
}
return params;
}
/**
* 拼接where条件
* @param filterColumns
* @return
*/
private static String buildSqlWhere(Set<String> filterColumns, LinkedHashMap<String, Object> params) {
List<String> sql = new ArrayList<>();
if (CollectionUtil.isEmpty(params)) {
return "";
}
for (String column : params.keySet()) {
if (null != filterColumns && !filterColumns.contains(column)) {
continue;
}
Object value = params.get(column);
if (null == value) {
sql.add(String.format("`%s` is null", column));
} else {
sql.add(String.format("`%s` = :%s", column, column));
}
}
if (sql.isEmpty()) {
return "";
}
return "where " + sql.stream().collect(Collectors.joining(" and "));
}
/**
* 拼接sql设置值的部分
* @param filterColumns
* @param params
* @return
*/
private static String buildSqlSet(Set<String> filterColumns, LinkedHashMap<String, Object> params) {
List<String> sql = new ArrayList<>();
if (CollectionUtil.isEmpty(filterColumns)) {
return "";
}
for (String column : filterColumns) {
Object value = params.get(column);
if (null == value) {
sql.add(String.format("`%s` = null"));
} else {
sql.add(String.format("%s = :%s", column, column));
}
}
if (sql.isEmpty()) {
return "";
}
return "set " + sql.stream().collect(Collectors.joining(","));
}
/**
* 拼接字段
* @param filterColumns
* @return
*/
private static String buildSqlColumns(Set<String> filterColumns) {
return filterColumns.stream().map(s -> String.format("`%s`", s)).collect(Collectors.joining(","));
}
/**
* 值处理
* @param value
* @return
*/
private static String sqlValueProcess(Object value) {
if (null == value) {
return "null";
} else if (value instanceof Date) {
return String.format("'%s'", DateUtil.format((Date)value, "yyyy-MM-dd HH:mm:ss"));
}
String res = String.valueOf(value).replaceAll("'", "\\\\\\\\'");
return "'" + res + "'";
}
/**
* 获取values后面的sql语句
* @param filterColumns
* @param params
* @return
*/
private static String getSqlValue(Set<String> filterColumns, LinkedHashMap<String, Object> params) {
List<String> list = new ArrayList<>();
for (String column : filterColumns) {
list.add(sqlValueProcess(params.get(column)));
}
return "(" + list.stream().collect(Collectors.joining(",")) + ")";
}
/**
* sql模板处理
* @param template
* @param params
* @return
*/
private static String templateProcess(String template, Map<String, String> params) {
if (StringUtil.isEmpty(template) || CollectionUtil.isEmpty(params)) {
return template;
}
for (String key : params.keySet()) {
template = template.replaceAll(String.format("\\$\\{%s\\}", key), params.get(key));
}
return template;
}
}
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.template;
import fun.asgc.neutrino.core.db.dao.DBType;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* 数据源持有者
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class DataSourceHolder {
/**
* 数据源
*/
private DataSource dataSource;
/**
* 是否保持连接
* 默认执行完SQL操作就归还连接
* 在开启事务的情况下,事务操作完毕才能归还
*/
private ThreadLocal<Boolean> keepConnectionCache = new ThreadLocal<>();
/**
* 数据库类型
*/
private DBType dbType;
public DataSourceHolder(DataSource dataSource) {
this.dataSource = dataSource;
}
public DataSourceHolder(DataSource dataSource, DBType dbType) {
this.dataSource = dataSource;
this.dbType = dbType;
}
public Connection getConnection() throws SQLException {
return this.dataSource.getConnection();
}
public void close(Connection conn) throws SQLException {
conn.close();
}
public void tryClose(Connection conn) throws SQLException {
Boolean keepConnection = keepConnectionCache.get();
if (null == keepConnection || !keepConnection) {
conn.close();
}
}
public void setKeepConnection(Boolean keepConnection) {
this.keepConnectionCache.set(keepConnection);
}
public DBType getDbType() {
return dbType;
}
public void setDbType(DBType dbType) {
this.dbType = dbType;
}
}
@@ -50,6 +50,7 @@ public class DbCache {
private static final String GROUP_TABLE_NAME_FROM = "GROUP_TABLE_NAME_FROM";
private static final Cache<Class<?>, Cache<Field, String>> fieldToColumnCache = new MemoryCache<>();
private static final Object fieldToColumnCacheLock = new Object();
private static final Cache<Class<?>,String> classTableNameCache = new MemoryCache<>();
/**
* 转换为列名
@@ -99,11 +100,20 @@ public class DbCache {
* @return
*/
public static String toTableName(Class<?> clazz) {
Table table = clazz.getAnnotation(Table.class);
if (null != table && StringUtil.notEmpty(table.value())) {
return table.value();
}
return toTableName(TypeUtil.getSimpleName(clazz));
return LockUtil.doubleCheckProcess(() -> !classTableNameCache.containsKey(clazz),
clazz,
() -> {
Table table = clazz.getAnnotation(Table.class);
String tableName;
if (null != table && StringUtil.notEmpty(table.value())) {
tableName = table.value();
} else {
tableName = toTableName(TypeUtil.getSimpleName(clazz));
}
classTableNameCache.set(clazz, tableName);
},
() -> classTableNameCache.get(clazz)
);
}
/**
@@ -170,6 +180,20 @@ public class DbCache {
);
}
/**
* 根据类获取字段缓存
* @param clazz
* @return
*/
public static Cache<Field, String> getFieldCache(Class<?> clazz) {
return LockUtil.doubleCheckProcess(
() -> !fieldToColumnCache.containsKey(clazz),
clazz,
() -> initFieldCache(clazz),
() -> fieldToColumnCache.get(clazz)
);
}
public static String getColumnNameByField(Field field) {
return LockUtil.doubleCheckProcess(
() -> !fieldToColumnCache.containsKey(field.getDeclaringClass()),
@@ -79,7 +79,7 @@ public class JdbcOperations {
try{
res = ps.executeUpdate();
}catch(SQLException e){
e.printStackTrace();
throw new RuntimeException(e);
}
return res;
}
@@ -213,7 +213,7 @@ public class JdbcOperations {
}
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
return res;
@@ -34,18 +34,21 @@ import java.util.Map;
* @date: 2022/6/27
*/
public class JdbcTemplate {
/**
* 数据源
* 数据源持有者
*/
private DataSource dataSource;
private DataSourceHolder dataSourceHolder;
/**
* jdbc操作
*/
private JdbcOperations jdbcOperations;
public JdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
this(new DataSourceHolder(dataSource));
}
public JdbcTemplate(DataSourceHolder dataSourceHolder) {
this.dataSourceHolder = dataSourceHolder;
this.jdbcOperations = JdbcOperations.getInstance();
}
@@ -54,23 +57,31 @@ public class JdbcTemplate {
Connection conn = null;
try {
conn = dataSource.getConnection();
conn = dataSourceHolder.getConnection();
res = jdbcOperations.executeUpdate(conn,sql, params);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
dataSourceHolder.tryClose(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
return res;
}
public int update(SqlAndParams sqlAndParams) {
return update(sqlAndParams.getSql(), sqlAndParams.getParamArray());
}
public int updateByMap(String sql, Map<String,Object> params){
SqlAndParams sqlAndParams = new SqlAndParams(sql, params);
return update(sqlAndParams.getSql(),sqlAndParams.getParamArray());
return update(new SqlAndParams(sql, params));
}
public int updateByModel(String sql, Object model){
SqlAndParams sqlAndParams = new SqlAndParams(sql, model);
return update(sqlAndParams.getSql(),sqlAndParams.getParamArray());
return update(new SqlAndParams(sql, model));
}
public <T> T query(Class<T> clazz, String sql, Object ...params){
@@ -78,23 +89,31 @@ public class JdbcTemplate {
Connection conn = null;
try {
conn = dataSource.getConnection();
res = jdbcOperations.executeQuery(conn,clazz,sql, params);
conn = dataSourceHolder.getConnection();
res = jdbcOperations.executeQuery(conn, clazz,sql, params);
} catch (SQLException e) {
new RuntimeException(e);
} finally {
try {
dataSourceHolder.tryClose(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
return res;
}
public <T> T query(Class<T> clazz, SqlAndParams sqlAndParams) {
return query(clazz, sqlAndParams.getSql(), sqlAndParams.getParamArray());
}
public <T> T queryByMap(Class<T> clazz, String sql, Map<String,Object> params){
SqlAndParams sqlAndParams = new SqlAndParams(sql, params);
return query(clazz,sqlAndParams.getSql(), sqlAndParams.getParamArray());
return query(clazz, new SqlAndParams(sql, params));
}
public <T> T queryByModel(Class<T> clazz, String sql, Object model){
SqlAndParams sqlAndParams = new SqlAndParams(sql, model);
return query(clazz, sqlAndParams.getSql(), sqlAndParams.getParamArray());
return query(clazz, new SqlAndParams(sql, model));
}
public byte queryForByteByMap(String sql, Map<String,Object> params){
@@ -242,15 +261,25 @@ public class JdbcTemplate {
Connection conn = null;
try {
conn = dataSource.getConnection();
conn = dataSourceHolder.getConnection();
res = jdbcOperations.executeQueryForList(conn, clazz, sql, params);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
dataSourceHolder.tryClose(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
return res;
}
public <T> List<T> queryForList(Class<T> clazz, SqlAndParams sqlAndParams) {
return queryForList(clazz, sqlAndParams.getSql(), sqlAndParams.getParamArray());
}
public <T> List<T> queryForListByMap(Class<T> clazz, String sql, Map<String,Object> params){
SqlAndParams sqlAndParams = new SqlAndParams(sql, params);
return queryForList(clazz, sqlAndParams.getSql(), sqlAndParams.getParamArray());
@@ -21,11 +21,11 @@
*/
package fun.asgc.neutrino.core.db.template;
import fun.asgc.neutrino.core.util.ArrayUtil;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
*
@@ -45,27 +45,25 @@ public abstract class PreparedStatementJdbcCallback<T> implements JdbcCallback<T
try {
log.debug("sql:" + this.getSql());
StringBuffer sb = new StringBuffer();
for(Object o : params){
sb.append(o.toString()).append(",");
}
if (ArrayUtil.notEmpty(params)) {
for(Object o : params){
sb.append(o.toString()).append(",");
}
if(sb.length() > 0 && sb.charAt(sb.length() - 1) == ','){
sb.deleteCharAt(sb.length() - 1);
if(sb.length() > 0 && sb.charAt(sb.length() - 1) == ','){
sb.deleteCharAt(sb.length() - 1);
}
}
log.debug("params:" + sb.toString());
pstm = conn.prepareStatement(this.getSql());
for(int i = 0;i < params.length;i++){
pstm.setObject(i + 1, params[i]);
if (ArrayUtil.notEmpty(params)) {
for(int i = 0;i < params.length;i++){
pstm.setObject(i + 1, params[i]);
}
}
res = this.execute(pstm);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
throw new RuntimeException(e);
}
return res;
@@ -51,6 +51,10 @@ public class SqlAndParams {
this.paramArray = paramArray;
}
public SqlAndParams(String sql) {
this.sql = sql;
}
public SqlAndParams(String sql,Map<String,Object> paramMap) {
this.sql = sql;
this.paramMap = paramMap;
@@ -78,6 +82,9 @@ public class SqlAndParams {
}
private void initParams() {
if (null == paramMap) {
paramMap = new HashMap<>();
}
List<Orderly> orderlyList = new ArrayList<>();
for(String key : paramMap.keySet()){
int index = sql.indexOf(":" + key);
@@ -97,4 +104,14 @@ public class SqlAndParams {
public String getSql(){
return sql;
}
@Override
public String toString() {
return "SqlAndParams{" +
"sql='" + sql + '\'' +
", paramArray=" + Arrays.toString(paramArray) +
", paramMap=" + paramMap +
", paramObject=" + paramObject +
'}';
}
}
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.util;
import fun.asgc.neutrino.core.cache.Cache;
import fun.asgc.neutrino.core.cache.MemoryCache;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class DateUtil {
private static final Cache<String, SimpleDateFormat> sdfCache = new MemoryCache<>();
private static SimpleDateFormat getSimpleDateFormat(String format) {
return LockUtil.doubleCheckProcess(
() -> !sdfCache.containsKey(format),
format,
() -> sdfCache.set(format, new SimpleDateFormat(format)),
() -> sdfCache.get(format)
);
}
/**
* 日期格式化
* @param date
* @param format
* @return
*/
public static String format(Date date, String format) {
try {
return getSimpleDateFormat(format).format(date);
} catch (Exception e) {
// ignore
}
return "";
}
}
@@ -0,0 +1,137 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
import com.alibaba.druid.pool.DruidDataSource;
import fun.asgc.neutrino.core.db.annotation.Column;
import fun.asgc.neutrino.core.db.annotation.Id;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.junit.Test;
import java.util.Date;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class DaoTest {
private DruidDataSource dataSource;
private DBType dbType;
{
dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("YWasgc@10520");
dbType = DBType.MYSQL;
}
@Test
public void add() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
User user = new User();
user.setId(4L);
user.setName("赵六");
user.setAge(24);
user.setEmail("[email protected]");
user.setSex("");
user.setCreateTime22(new Date());
userDao.add(user);
}
@Test
public void findOneById() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
User user = userDao.findOneById(3);
System.out.println(user);
}
@Test
public void findOne1() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
User user = userDao.findOne(new User()
.setId(1L), "id");
System.out.println(user);
}
@Test
public void findOne2() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
User user = userDao.findOne(new User()
.setAge(23), "age");
System.out.println(user);
}
@Test
public void findOne3() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
User user = userDao.findOne(new User()
.setAge(23)
.setName("张三"), "age", "name");
System.out.println(user);
}
@Test
public void find1() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
List<User> userList = userDao.find();
System.out.println(userList);
}
@Test
public void find2() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
List<User> userList = userDao.find(new User().setAge(21), "age");
System.out.println(userList);
}
@Test
public void count1() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
System.out.println(userDao.count());
}
@Test
public void count2() {
Dao<User> userDao = new DefaultDaoImpl<>(dataSource, dbType, User.class);
System.out.println(userDao.count(new User().setAge(21), "age"));
}
@ToString
@Accessors(chain = true)
@Data
public static class User {
@Id
private Long id;
private String name;
private Integer age;
private String email;
private String sex;
@Column("create_time")
private Date createTime22;
private Date updateTime;
}
}
@@ -0,0 +1,63 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.db.dao;
import fun.asgc.neutrino.core.db.annotation.Id;
import lombok.Data;
import lombok.experimental.Accessors;
import org.junit.Test;
import java.util.Date;
/**
*
* @author: aoshiguchen
* @date: 2022/6/28
*/
public class SqlDialectForMysqlTest {
@Test
public void test1() {
SqlDialect sqlDialect = new SqlDialectForMysql();
User user = new User();
user.setName("11'");
user.setAge(20);
user.setSex("");
user.setEmail("[email protected]");
user.setCreateTime(new Date());
System.out.println(sqlDialect.add(user));
}
@Accessors(chain = true)
@Data
public static class User {
@Id
private Long id;
private String name;
private Integer age;
private String email;
private String sex;
private Date createTime;
private Date updateTime;
}
}