增加ColumnValue功能

This commit is contained in:
Redkale
2016-10-31 13:32:08 +08:00
parent de5a725acc
commit 19150e9f9c
7 changed files with 315 additions and 26 deletions

View File

@@ -63,6 +63,16 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
source.updateColumn(clazz, column, value, node);
}
@Override
public <T> void updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
source.updateColumn(clazz, id, values);
}
@Override
public <T> void updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
source.updateColumn(clazz, node, values);
}
@Override
public <T> void updateColumnIncrement(final Class<T> clazz, final Serializable id, final String column, long incvalue) {
source.updateColumnIncrement(clazz, id, column, incvalue);

View File

@@ -0,0 +1,21 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.source;
/**
* 函数表达式, 均与SQL定义中的表达式相同
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public enum ColumnExpress {
MOV, //直接赋值 col = val
INCR, //追加值 col = col + val
AND, //与值 col = col & val
OR; //或值 col = col | val
}

View File

@@ -0,0 +1,67 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.source;
import java.io.Serializable;
/**
* ColumnValue主要用于多个字段更新的表达式。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class ColumnValue {
private String column;
private ColumnExpress express;
private Serializable value;
public ColumnValue() {
}
public ColumnValue(String column, Serializable value) {
this(column, ColumnExpress.MOV, value);
}
public ColumnValue(String column, ColumnExpress express, Serializable value) {
this.column = column;
this.express = express == null ? ColumnExpress.MOV : express;
this.value = value;
}
public String getColumn() {
return column;
}
public void setColumn(String column) {
this.column = column;
}
public ColumnExpress getExpress() {
return express;
}
public void setExpress(ColumnExpress express) {
this.express = express;
}
public Serializable getValue() {
return value;
}
public void setValue(Serializable value) {
this.value = value;
}
@Override
public String toString() {
return "{\"column\":\"" + column + "\", \"express\":" + express + ", \"value\":" + ((value instanceof CharSequence) ? ("\"" + value + "\"") : value) + "}";
}
}

View File

@@ -731,6 +731,124 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
}
}
/**
* 根据主键值更新对象的多个column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param id 主键值
* @param values 字段值
*/
@Override
public <T> void updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
updateColumn(null, info, id, values);
return;
}
Connection conn = createWriteSQLConnection();
try {
updateColumn(conn, info, id, values);
} finally {
closeSQLConnection(conn);
}
}
private <T> void updateColumn(final Connection conn, final EntityInfo<T> info, final Serializable id, final ColumnValue... values) {
if (values == null || values.length < 1) return;
try {
StringBuilder setsql = new StringBuilder();
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>();
final boolean virtual = info.isVirtualEntity();
for (ColumnValue col : values) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue;
attrs.add(attr);
cols.add(col);
if (!virtual) {
if (setsql.length() > 0) setsql.append(", ");
setsql.append(info.getSQLColumn(null, col.getColumn())).append(" = ").append(info.formatToString(col.getValue()));
}
}
if (!virtual) {
String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get()) logger.finest(info.getType().getSimpleName() + ": " + sql);
final Statement stmt = conn.createStatement();
stmt.execute(sql);
stmt.close();
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return;
T rs = cache.updateColumn(id, attrs, cols);
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 根据主键值更新对象的多个column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param node 过滤条件
* @param values 字段值
*/
@Override
public <T> void updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
updateColumn(null, info, node, values);
return;
}
Connection conn = createWriteSQLConnection();
try {
updateColumn(conn, info, node, values);
} finally {
closeSQLConnection(conn);
}
}
private <T> void updateColumn(final Connection conn, final EntityInfo<T> info, final FilterNode node, final ColumnValue... values) {
if (values == null || values.length < 1) return;
try {
StringBuilder setsql = new StringBuilder();
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>();
final boolean virtual = info.isVirtualEntity();
for (ColumnValue col : values) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue;
attrs.add(attr);
cols.add(col);
if (!virtual) {
if (setsql.length() > 0) setsql.append(", ");
setsql.append(info.getSQLColumn("a", col.getColumn())).append(" = ").append(info.formatToString(col.getValue()));
}
}
if (!virtual) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, joinTabalis, info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
String sql = "UPDATE " + info.getTable(node) + " a SET " + setsql + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get()) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
final Statement stmt = conn.createStatement();
stmt.execute(sql);
stmt.close();
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return;
T[] rs = cache.updateColumn(node, attrs, cols);
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 根据主键值给对象的column对应的值+incvalue 必须是Entity Class
* 等价SQL: UPDATE {clazz} SET {column} = {column} + {incvalue} WHERE {primary} = {id}

View File

@@ -66,6 +66,10 @@ public interface DataSource {
public <T> void updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node);
public <T> void updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values);
public <T> void updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values);
public <T> void updateColumnIncrement(final Class<T> clazz, final Serializable id, final String column, long incvalue);
public <T> void updateColumnAnd(final Class<T> clazz, final Serializable id, final String column, long incvalue);

View File

@@ -387,15 +387,19 @@ public final class EntityCache<T> {
if (value == null) return;
T rs = this.map.get(this.primary.get(value));
if (rs == null) return;
this.chgReproduce.apply(rs, value);
synchronized (rs) {
this.chgReproduce.apply(rs, value);
}
}
public T update(final T value, Collection<Attribute<T, Serializable>> attrs) {
if (value == null) return value;
T rs = this.map.get(this.primary.get(value));
if (rs == null) return rs;
for (Attribute attr : attrs) {
attr.set(rs, attr.get(value));
synchronized (rs) {
for (Attribute attr : attrs) {
attr.set(rs, attr.get(value));
}
}
return rs;
}
@@ -404,8 +408,10 @@ public final class EntityCache<T> {
if (value == null || node == null) return (T[]) Array.newInstance(type, 0);
T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len));
for (T rs : rms) {
for (Attribute attr : attrs) {
attr.set(rs, attr.get(value));
synchronized (rs) {
for (Attribute attr : attrs) {
attr.set(rs, attr.get(value));
}
}
}
return rms;
@@ -427,46 +433,109 @@ public final class EntityCache<T> {
return rms;
}
public <V> T updateColumn(final Serializable id, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
if (id == null || attrs == null || attrs.isEmpty()) return null;
T rs = this.map.get(id);
if (rs == null) return rs;
synchronized (rs) {
for (int i = 0; i < attrs.size(); i++) {
ColumnValue cv = values.get(i);
updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue());
}
}
return rs;
}
public <V> T[] updateColumn(final FilterNode node, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0);
T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len));
for (T rs : rms) {
synchronized (rs) {
for (int i = 0; i < attrs.size(); i++) {
ColumnValue cv = values.get(i);
updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue());
}
}
}
return rms;
}
public <V> T updateColumnOr(final Serializable id, Attribute<T, V> attr, final long orvalue) {
if (id == null) return null;
T rs = this.map.get(id);
if (rs == null) return rs;
Number numb = (Number) attr.get(rs);
return updateColumnIncrAndOr(attr, rs, (numb == null) ? orvalue : (numb.longValue() | orvalue));
synchronized (rs) {
return updateColumn(attr, rs, ColumnExpress.OR, orvalue);
}
}
public <V> T updateColumnAnd(final Serializable id, Attribute<T, V> attr, final long andvalue) {
if (id == null) return null;
T rs = this.map.get(id);
if (rs == null) return rs;
Number numb = (Number) attr.get(rs);
return updateColumnIncrAndOr(attr, rs, (numb == null) ? 0 : (numb.longValue() & andvalue));
synchronized (rs) {
return updateColumn(attr, rs, ColumnExpress.AND, andvalue);
}
}
public <V> T updateColumnIncrement(final Serializable id, Attribute<T, V> attr, final long incvalue) {
if (id == null) return null;
T rs = this.map.get(id);
if (rs == null) return rs;
Number numb = (Number) attr.get(rs);
return updateColumnIncrAndOr(attr, rs, (numb == null) ? incvalue : (numb.longValue() + incvalue));
synchronized (rs) {
return updateColumn(attr, rs, ColumnExpress.INCR, incvalue);
}
}
private <V> T updateColumnIncrAndOr(Attribute<T, V> attr, final T rs, Number numb) {
private <V> T updateColumn(Attribute<T, V> attr, final T rs, final ColumnExpress express, Serializable val) {
final Class ft = attr.type();
if (ft == int.class || ft == Integer.class) {
numb = numb.intValue();
} else if (ft == long.class || ft == Long.class) {
numb = numb.longValue();
} else if (ft == short.class || ft == Short.class) {
numb = numb.shortValue();
} else if (ft == float.class || ft == Float.class) {
numb = numb.floatValue();
} else if (ft == double.class || ft == Double.class) {
numb = numb.doubleValue();
} else if (ft == byte.class || ft == Byte.class) {
numb = numb.byteValue();
Number numb = null;
Serializable newval = null;
switch (express) {
case INCR:
numb = (Number) attr.get(rs);
if (numb == null) {
numb = (Number) val;
} else {
numb = numb.longValue() + ((Number) val).longValue();
}
break;
case AND:
numb = (Number) attr.get(rs);
if (numb == null) {
numb = 0;
} else {
numb = numb.longValue() & ((Number) val).longValue();
}
break;
case OR:
numb = (Number) attr.get(rs);
if (numb == null) {
numb = 0;
} else {
numb = numb.longValue() | ((Number) val).longValue();
}
break;
case MOV:
newval = val;
break;
}
attr.set(rs, (V) numb);
if (numb != null) {
if (ft == int.class || ft == Integer.class) {
newval = numb.intValue();
} else if (ft == long.class || ft == Long.class) {
newval = numb.longValue();
} else if (ft == short.class || ft == Short.class) {
newval = numb.shortValue();
} else if (ft == float.class || ft == Float.class) {
newval = numb.floatValue();
} else if (ft == double.class || ft == Double.class) {
newval = numb.doubleValue();
} else if (ft == byte.class || ft == Byte.class) {
newval = numb.byteValue();
}
}
attr.set(rs, (V) newval);
return rs;
}

View File

@@ -22,7 +22,7 @@ import org.redkale.util.Attribute;
*
* @author zhangjx
*/
public class FilterNode {
public class FilterNode { //FilterNode 不能实现Serializable接口 否则DataSource很多重载接口会出现冲突
protected String column;