经历一个挺有意思的项目学习了另外一种可以更加合理的操作数据的方法下面是最近的项目总结。
需求:
需要我制作一个功能,要求能够进行数据库的update和delete操作,但是要求能够备份对应的数据,并且做好异常捕捉。
实现:
功能在使用的时候对于功能进行限制,要求将需要进行操作预置到指定的数据库表中,我们在前台进行展示,不会限制where以后的条件,但是做好删除或者更新字段的限制,这样可以最大程度的是功能变成强大并且能够合理的限制这个功能,避免有的用户恶意进行删除。
前段设计
就是在数据库中预支对应的字段,但是对于字段的修改之前一直没有想法,因为最初的设想是需要把需要更改的字段放到数据库中的一个一行记录的一个字段中,但是前段怎么使用确实是没有想好。因为我们的前段确实很难,至少我认为很难,动态生成文本框其实是可以的,但是要的急没有时间去思考我就用了最愚蠢的办法,
直接新建了10个文本框来处理,只需要控制文本框的显隐问题就可以了,这样前段的问题其实就处理完了。
后端设计
其实我认为难点在后端,我要修改或者删除记录,功能读取数据库的表中的记录,前段输入筛选条件,进行删除或者更新记录的时候,需要将需要更改或者删除的记录备份起来,然后在进行这个操作。难点就在备份这个问题上面了,首先我们需要先备份一下原来的表,其次如果有之前的表,我们要将我们的要修改的数据或者要删除的数据插入到备份的表中,这就要求我们去新建一个跟我们要操作表表结构一样的表,并且要多几个字段,要记录这个操作是修改还是删除,操作的时间,只有当备份表成功生成并且将将备份数据成功插入,才可以对于旧的表进行更新或者删除操作。
新建表
@Transactional
@Modifying
public JSONObject createTablename(String tablenameOld,String tablenameNew) {
int i = entityManager.createNativeQuery("create table"+" "+tablenameNew+" "+" as select * from "+" "+tablenameOld+" "+" where 1=2").executeUpdate();
int i1 = entityManager.createNativeQuery("alter table "+" "+tablenameNew+" "+" add (altertable_type varchar2(10),altertable_name varchar2(50),altertable_time varchar2(40))").executeUpdate();
alterTableType(tablenameNew);
return null;
}
这个其实是包括了新建表和添加字段,一定一定不能够忘记上面的两个备注@Transactional @Modifying 一定不要忘记否则会提示报错。
修改表结构
@Transactional
@Modifying
public JSONObject alterTableType(String tablenameNew) {
JSONObject result = new JSONObject();
String sql = "select COLUMN_NAME as name,DATA_TYPE as type from user_tab_columns where table_name =upper('"+tablenameNew+"')";
javax.persistence.Query query = entityManager.createNativeQuery(sql);
query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List<Map> rows = query.getResultList();
for (int i = 0; i < rows.size(); i++) {
Map map = rows.get(i);
if(map.get("TYPE").toString().length()>=4){
if(map.get("TYPE").toString().substring(0,4).equals("DATE")){
int i1 = entityManager.createNativeQuery("alter table "+" "+tablenameNew+" "+" modify ("+" "+map.get("NAME")+" "+" varchar2(30))").executeUpdate();
}
if(map.get("TYPE").toString().length()>=9&&map.get("TYPE").toString().substring(0,9).equals("TIMESTAMP")){
int i1 = entityManager.createNativeQuery("alter table "+" "+tablenameNew+" "+" modify ("+" "+map.get("NAME")+" "+" varchar2(30))").executeUpdate();
}
}
}
return null;
}
为什么要修改表结构呢?是因为我发现我从用这个方法拿到的数据办法插入到对应的数据中去,主要是时间戳这个字段,而且时间紧急,就直接把表结构改了,这是下下策但是确实好用,正好用。
select COLUMN_NAME as name,DATA_TYPE as type from user_tab_columns where table_name =upper('"+tablenameNew+"') 这个是用来吧oracle中对应表的表结构查出来,但是注意查出来的都是大写可以看到我get的时候就是大写,我获取的也都是大写。
删除表
@Transactional
@Modifying
public JSONObject dropTablename(String tablename) {
int i = entityManager.createNativeQuery("drop table "+" "+tablename).executeUpdate();
return null;
}
就不多说了
查询
@Transactional
@Modifying
public JSONObject selectTablename(String tablenameOld , String tablenameNew) {
JSONObject result = new JSONObject();
try {
String sql = "select count(*) from user_tables where table_name =upper('"+tablenameNew+"')";
javax.persistence.Query query = entityManager.createNativeQuery(sql);
query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List<Map> rows = query.getResultList();
String count = rows.get(0).get("COUNT(*)").toString();
if("0".equals(count)){
result.put("status","false");
result.put("message","不存在对应表");
return result;
}else {
JSONObject jsonObject = compareTableStructure(tablenameOld, tablenameNew);
return jsonObject;
}
}catch (Exception sqlex) {
result.put("status","false");
result.put("message","不存在对应表");
return result;
}
}
这个操作是为了查询这个表是否存在,就是我们需要去验证他们在数据库中预置数据中表名字段是否正确,而且为了不报异常,我们可以直接select * from tablename 但是会提示异常,你就会发现你写的事务的注解就生效了,你就没啥可以做的了,虽然确实应该生效但是我觉得会有更好的方法处理我们就应该用好的办法处理
插入
@Transactional
@Modifying
public JSONObject insertIntotablenameNew(List<Map> rows,String tablenameNew,String datagovernancetype) {
try{
StringBuilder rowsName = new StringBuilder();
StringBuilder rowsValue = new StringBuilder();
for (int i = 0; i < rows.size(); i++) {
Map map = rows.get(i);
for (Object o : map.keySet()) {
rowsName.append( ","+o.toString());
Object o1 = map.get(o);
if(StringUtils.isEmpty(o1)){
rowsValue.append(", ''");
}else{
rowsValue.append( ",'"+o1.toString()+"'");
}
}
}
if("1".equals(datagovernancetype)){
rowsName.append(",altertable_type");
rowsValue.append( ",'delete'");
}else{
rowsName.append(",altertable_type");
rowsValue.append( ",'update'");
}
rowsName.append(",altertable_time");
Date date =new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(date);
rowsValue.append(",'"+format);
rowsValue.append("'");
String substringRowsName = rowsName.substring(1);
String substringRowsValue = rowsValue.substring(1);
String sql = "insert into "+" "+tablenameNew+" "+"("+" "+substringRowsName+" "+") values ("+" "+substringRowsValue+" "+")";
int i = entityManager.createNativeQuery(sql).executeUpdate();
JSONObject jsonObject =new JSONObject();
jsonObject.put("status","true");
return jsonObject;
}
catch (Exception e){
JSONObject jsonObject =new JSONObject();
jsonObject.put("status","false");
return jsonObject;
}
}
插入,这个方法的作用是为了将我们查出来的时候进行插入,插入到我们的备份表中,
删除和修改
@Transactional
@Modifying
public int updatetablenameOld(String tablenameOld,String datagovernancetype,String condition,String[] split,JSONArray jsonArray) {
int res =0;
String sql = "";
if("1".equals(datagovernancetype)){
sql = "delete from "+" "+tablenameOld+" "+"where"+" "+condition;
res = entityManager.createNativeQuery(sql).executeUpdate();
return res;
}else{
sql = "update "+" "+tablenameOld+" "+"set";
for (int i = 0; i < split.length; i++) {
String splits = split[i];
for (int j = 0; j < jsonArray.size(); j++) {
JSONObject jsonObject = jsonArray.getJSONObject(j);
String key = jsonObject.getString("key");
if(key.equals(splits)){
sql = sql +" "+jsonObject.getString("key")+" "+"="+" '"+jsonObject.getString("value")+"' "+",";
}
}
}
sql = sql.substring(0,sql.length()-1);
sql = sql+"where"+" "+condition;
res = entityManager.createNativeQuery(sql).executeUpdate();
return res;
}
}
这里把删除和修改放在了一起,可以看到其实就是简单的字符串拼接。
注意
一定要注意这种写法的问题,这种写法一定要注意加空格,要不然直接就是在一起,就导致他的关键字识别不出来,你们可能会问entityManager 是啥,我只能够提供一个@PersistenceContext private EntityManager entityManager; 有兴趣的各位可以去搜一搜。
不足
其实还是有很多的不足的,希望大家指出来,一个表的结构被修改了,增加了字段或者字段增加了长度,导致我们备份失败,我们应该如何处理,重新建一张表用来存放内容吗?还是增加对应的字段?时间类型如何成功插入到数据库中?备份的数据应该存留预置数据的id吗?备份的数据应该保留筛选条件吗?很多的问题其实都是可以去优化的
|