All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pugwoo.dbhelper.impl.part.P5_DeleteOp Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package com.pugwoo.dbhelper.impl.part;

import com.pugwoo.dbhelper.DBHelper;
import com.pugwoo.dbhelper.DBHelperInterceptor;
import com.pugwoo.dbhelper.annotation.Column;
import com.pugwoo.dbhelper.annotation.Table;
import com.pugwoo.dbhelper.exception.InvalidParameterException;
import com.pugwoo.dbhelper.exception.NotAllowModifyException;
import com.pugwoo.dbhelper.exception.NullKeyValueException;
import com.pugwoo.dbhelper.exception.SpringBeanNotMatchException;
import com.pugwoo.dbhelper.json.NimbleOrmJSON;
import com.pugwoo.dbhelper.sql.SQLAssert;
import com.pugwoo.dbhelper.sql.SQLUtils;
import com.pugwoo.dbhelper.utils.DOInfoReader;
import com.pugwoo.dbhelper.utils.InnerCommonUtils;
import com.pugwoo.dbhelper.utils.PreHandleObject;

import java.lang.reflect.Field;
import java.util.*;

public abstract class P5_DeleteOp extends P4_InsertOrUpdateOp {

	/////// 拦截器

	private  void doInterceptBeforeDelete(T t) {
		if (InnerCommonUtils.isEmpty(interceptors)) {
			return;
		}
		List tList = new ArrayList<>();
		tList.add(t);
		doInterceptBeforeDelete(tList);
	}

	private void doInterceptBeforeDelete(List tList) {
		for (DBHelperInterceptor interceptor : interceptors) {
			boolean isContinue = interceptor.beforeDelete(tList);
			if (!isContinue) {
				throw new NotAllowModifyException("interceptor class:" + interceptor.getClass());
			}
		}
	}

	private  void doInterceptAfterDelete(final T t, final int rows) {
		if (InnerCommonUtils.isEmpty(interceptors)) {
			return;
		}
		List tList = new ArrayList<>();
		tList.add(t);
		doInterceptAfterDelete(tList, rows);
	}

	private void doInterceptAfterDelete(final List tList, final int rows) {
		if (InnerCommonUtils.isEmpty(interceptors)) {
			return; // 内部实现尽量不调用executeAfterCommit
		}
		Runnable runnable = () -> {
			for (int i = interceptors.size() - 1; i >= 0; i--) {
				interceptors.get(i).afterDelete(tList, rows);
			}
		};
		if(!executeAfterCommit(runnable)) {
			runnable.run();
		}
	}

	/////////// END 拦截器

	@Override
	public  int delete(T t) throws NullKeyValueException {
		return _delete(t, false);
	}

	@Override
	public  int deleteHard(T t) throws NullKeyValueException {
		return _delete(t, true);
	}

	private  int _delete(T t, boolean isHard) throws NullKeyValueException {
		if (t == null) {
			throw new InvalidParameterException("delete t is null");
		}

		PreHandleObject.preHandleDelete(t);

		doInterceptBeforeDelete(t);

		Field softDelete = DOInfoReader.getSoftDeleteColumn(t.getClass());

		String sql;
		List values = new ArrayList<>();
		if (isHard || softDelete == null) { // 物理删除
			sql = SQLUtils.getDeleteSQL(t, values);
		} else { // 软删除
			// 对于软删除,当有拦截器时,可能使用者会修改数据以记录删除时间或删除人信息等,此时要先update该条数据
			if(InnerCommonUtils.isNotEmpty(interceptors)) {
				updateForDelete(t);
			}
			Column softDeleteColumn = softDelete.getAnnotation(Column.class);
			sql = SQLUtils.getSoftDeleteSQL(t, softDeleteColumn, values);
		}

		Table table = DOInfoReader.getTable(t.getClass());
		if (!isHard && InnerCommonUtils.isNotBlank(table.softDeleteTable())) {
			// 将删除的数据存到另外一张表中
			DBHelper dbHelper = getDBHelper(table.softDeleteDBHelperBean());

			// 查回数据并插入到软删除表
			List keyParams = new ArrayList<>();
			String keysWhereSQL = SQLUtils.getKeysWhereSQL(t, keyParams);
			Object dbT = getOne(t.getClass(), keysWhereSQL, keyParams.toArray());
			try {
				if (dbT == null) {
					LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, data is null, key:{}",
							NimbleOrmJSON.toJson(keyParams));
				} else {
					Map, String> tableNames = new HashMap<>();
					tableNames.put(t.getClass(), table.softDeleteTable());
					DBHelper.withTableNames(tableNames, () -> {
						int rows = dbHelper.insert(dbT);
						if (rows != 1) {
							LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, rows={}, data: {}",
									rows, NimbleOrmJSON.toJson(dbT));
						}
					});
				}
			} catch (Exception e) {
				LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, data: {}",
						NimbleOrmJSON.toJson(dbT), e);
			}
		}

		int rows = jdbcExecuteUpdate(sql, values.toArray()); // 不会有in(?)表达式

		doInterceptAfterDelete(t, rows);
		return rows;
	}

	private DBHelper getDBHelper(String dbHelperBean) {
		DBHelper dbHelper = this;
		if (InnerCommonUtils.isNotBlank(dbHelperBean)) {
			Object bean = applicationContext.getBean(dbHelperBean);
			if (!(bean instanceof DBHelper)) {
				throw new SpringBeanNotMatchException("cannot find DBHelper bean: " + dbHelperBean
						+ " or it is not type of SpringJdbcDBHelper");
			} else {
				dbHelper = (DBHelper) bean;
			}
		}
		return dbHelper;
	}

	@Override
	public  int deleteHard(Collection list) throws NullKeyValueException {
		return _delete(list, true);
	}

	@Override
	public  int delete(Collection list) throws NullKeyValueException {
		return _delete(list, false);
	}

	private  int _delete(Collection list, boolean isHard) throws NullKeyValueException {
		if(list == null || list.isEmpty()) {
			return 0;
		}

		Class clazz = null; // 当batchDelete时使用
		for (T t : list) {
			if (t != null) {
				clazz = t.getClass();
			}
		}

		boolean batchDelete = false; // 当所有list都是一个类型,且key是1个,且没有用到deleteValueScript时
		Field keyField = null;
		if(SQLAssert.isAllSameClass(list)) {
			List keyFields = DOInfoReader.getKeyColumns(clazz);
			if(keyFields.size() == 1) {
				keyField = keyFields.get(0);

				boolean isUseDeleteValueScript = false;
				List fields = DOInfoReader.getColumns(clazz);
				for(Field field : fields) {
					Column column = field.getAnnotation(Column.class);
					if(InnerCommonUtils.isNotBlank(column.deleteValueScript())) {
						isUseDeleteValueScript = true;
						break;
					}
				}

				if(!isUseDeleteValueScript) {
					batchDelete = true;
				}
			}
		}

		if(batchDelete) {
			for(T t : list) {
				PreHandleObject.preHandleDelete(t);
			}

			List keys = new ArrayList<>();
			for(T t : list) {
				Object key = DOInfoReader.getValue(keyField, t);
				if(key != null) {
					keys.add(key);
				}
			}

			List listTmp = new ArrayList<>(list);
			doInterceptBeforeDelete(listTmp);

			Field softDelete = DOInfoReader.getSoftDeleteColumn(clazz); // 支持软删除

			String sql;
			String where = "where " + SQLUtils.getColumnName(keyField) + " in (?)";
			if(isHard || softDelete == null) { // 物理删除
				sql = SQLUtils.getCustomDeleteSQL(clazz, where);
			} else { // 软删除
				sql = SQLUtils.getCustomSoftDeleteSQL(clazz, where, softDelete);
			}

			Table table = DOInfoReader.getTable(clazz);
			if (!isHard && InnerCommonUtils.isNotBlank(table.softDeleteTable())) {
				// 将删除的数据存到另外一张表中
				DBHelper dbHelper = getDBHelper(table.softDeleteDBHelperBean());

				// 查回数据并插入到软删除表
				List all = dbHelper.getAll(clazz, where, keys.toArray());
				try {
					if (all == null || all.isEmpty()) {
						LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, data is null, key:{}",
								NimbleOrmJSON.toJson(keys));
					} else {
						Map, String> tableNames = new HashMap<>();
						tableNames.put(clazz, table.softDeleteTable());
						DBHelper.withTableNames(tableNames, () -> {
							int rows = dbHelper.insert(all);
							if (rows != all.size()) {
								LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, rows={}, data: {}",
										rows, NimbleOrmJSON.toJson(all));
							}
						});
					}
				} catch (Exception e) {
					LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, data: {}",
							NimbleOrmJSON.toJson(all), e);
				}
			}

			int rows = namedJdbcExecuteUpdate(sql, keys);

			doInterceptAfterDelete(listTmp, rows);
			return rows;
		} else {
			int rows = 0;
			for(T t : list) {
				rows += delete(t); // delete(t)中已经做了preHandleDelete和软删除到另外一张表
			}
			return rows;
		}
	}

	@Override
	public  int deleteHard(Class clazz, String postSql, Object... args) {
		return _delete(clazz, true, postSql, args);
	}

	@Override
	public  int delete(Class clazz, String postSql, Object... args) {
		return _delete(clazz, false, postSql, args);
	}

	private  int _delete(Class clazz, boolean isHard, String postSql, Object... args) {
		if(InnerCommonUtils.isBlank(postSql)) { // warning: very dangerous
			// 不支持缺省条件来删除。如果需要全表删除,请明确传入where 1=1
			throw new InvalidParameterException("delete postSql is blank. it's very dangerous. use WHERE 1=1 to confirm delete all");
		}

		Field softDelete = DOInfoReader.getSoftDeleteColumn(clazz); // 支持软删除
		String sql;

		if((interceptors == null || interceptors.isEmpty()) && !isUseDeleteValueScript(clazz)) { // 没有配置拦截器,则直接删除
			if(isHard || softDelete == null) { // 物理删除
				sql = SQLUtils.getCustomDeleteSQL(clazz, postSql);
			} else { // 软删除
				sql = SQLUtils.getCustomSoftDeleteSQL(clazz, postSql, softDelete);
			}

			Table table = DOInfoReader.getTable(clazz);
			if (!isHard && InnerCommonUtils.isNotBlank(table.softDeleteTable())) {
				// 将删除的数据存到另外一张表中
				DBHelper dbHelper = getDBHelper(table.softDeleteDBHelperBean());

				// 查回数据并插入到软删除表
				List all = dbHelper.getAll(clazz, postSql, args);
				try {
					if (all == null || all.isEmpty()) {
						LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, data is null, postSql:{}, args:{}",
								postSql, NimbleOrmJSON.toJson(args));
					} else {
						Map, String> tableNames = new HashMap<>();
						tableNames.put(clazz, table.softDeleteTable());
						DBHelper.withTableNames(tableNames, () -> {
							int rows = dbHelper.insert(all);
							if (rows != all.size()) {
								LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, rows={}, data: {}",
										rows, NimbleOrmJSON.toJson(all));
							}
						});
					}
				} catch (Exception e) {
					LOGGER.error("soft delete insert to table:" + table.softDeleteTable() + " error, data: {}",
							NimbleOrmJSON.toJson(all), e);
				}
			}

			return namedJdbcExecuteUpdate(sql, args);
		} else { // 配置了拦截器,则先查出key,再删除
			List allKey = getAllKey(clazz, postSql, args);
			return delete(allKey);
		}
	}

	private static boolean isUseDeleteValueScript(Class clazz) {
		List columns = DOInfoReader.getColumns(clazz);
		for (Field field : columns) {
			if (InnerCommonUtils.isNotBlank(field.getAnnotation(Column.class).deleteValueScript())) {
				return true;
			}
		}
		return false;
	}

	private  void updateForDelete(T t) throws NullKeyValueException {
		List values = new ArrayList<>();
		String sql = SQLUtils.getUpdateSQL(t, values, false, null);
		if (sql != null) {
			// 没有in (?),因此用jdbcExecuteUpdate
			jdbcExecuteUpdate(sql, values.toArray()); // ignore update result
		}
	}
}