Heim > Fragen und Antworten > Hauptteil
简单的说就是我要执行
update table set value = value + 1 where id = XXX
这样的语句,我在可是似乎并不是所有的ORM库都支持这种操作,举个栗子,我在rails里面有看到update可以支持传入+1、-1这样的参数。可是我在nodejs的jugglingdb里面居然没有找到。
MySQL.prototype.toFields = function (model, data) {
var fields = [];
var props = this._models[model].properties;
Object.keys(data).forEach(function (key) {
if (props[key]) {
var value = this.toDatabase(props[key], data[key]);
if ('undefined' === typeof value) return;
fields.push('`' + key.replace(/\./g, '`.`') + '` = ' + value);
}
}.bind(this));
return fields.join(',');
};
MySQL.prototype.toDatabase = function (prop, val) {
if (val === null) return 'NULL';
if (val === undefined) return;
if (val.constructor.name === 'Object') {
var operator = Object.keys(val)[0]
val = val[operator];
if (operator === 'between') {
return this.toDatabase(prop, val[0]) +
' AND ' +
this.toDatabase(prop, val[1]);
} else if (operator == 'inq' || operator == 'nin') {
if (!(val.propertyIsEnumerable('length')) && typeof val === 'object' && typeof val.length === 'number') { //if value is array
for (var i = 0; i < val.length; i++) {
val[i] = this.client.escape(val[i]);
}
return val.join(',');
} else {
return val;
}
}
}
if (!prop) return val;
if (prop.type.name === 'Number') return Number(val);
if (prop.type.name === 'Date') {
if (!val) return 'NULL';
if (!val.toUTCString) {
val = new Date(val);
}
return '"' + dateToMysql(val) + '"';
}
if (prop.type.name == "Boolean") return val ? 1 : 0;
if (typeof prop.type === 'function') return this.client.escape(prop.type(val));
return this.client.escape(val.toString());
};
可以看出,完全不支持。
可是这十分不应该,+1-1这种操作明显是需要线程安全的(nodejs的话就是进程级别了……)可是ORM的select操作是不带锁的(带了也没用啊……)这样出错的概率非常的大。要怎么解决这个问题?
我并不想对原有代码做太多改动,不然我也不会用ORM的库了,能否他通过一些技巧达到这个目的,或者有什么别的OR妈的库可以推荐的吗?
大家讲道理2017-04-17 11:03:05
不是很懂node和你用的框架,对于+1-1这种操作我见过两种方法,第一种比较粗暴的就是使用事务,事务会根据隔离等级对记录加上一个独占锁使得你的修改是安全的,就是悲观锁方案;还有一种乐观锁方案,就是先读取原值,update的时候在where条件里添加'value=老值'这样的限制条件,如果记录已经被别人修改了那么你的修改返回的影响行数会是0,你就知道修改失败了,要重新读取再修改了。悲观锁在高烈度竞争下性能比较好,乐观锁在低烈度竞争下性能比较好,视情况而定了。