我有一个DAO类,它有多个更新数据库表的方法。这些方法在整个代码库中以许多不同的顺序在许多不同的地方调用。
public class Dao {
public synchronized updateA()
public synchronized updateB()
public synchronized updateC()
public synchronized getA()
public synchronized getB()
public synchronized getC()
}
我遇到问题,Class1希望按顺序呼叫getA()
,getB()
和getC()
。三个表A,B和C是相关的,所以我需要在一个时间点使它们的状态同步。
但是,在Class1调用getA()
之后,在调用getB()
之前,另一个线程上的Class2跳入并调用updateB()
,这会破坏事情。
当有任何线程在那里时,是否可以锁定整个DAO类,并且只有在它完成后解锁它?
我已经尝试在DAO类中放置一个静态ReentrantLock并将其从Class1锁定,但我不确定如何从那里开始。
我已经达到了以下目标:
public class Class1 {
public void check() {
dao.daoLock.lock();
dao.getA();
dao.getB();
dao.getC();
dao.daoLock.unlock();
}
}
public class Dao {
public static final daoLock = new ReentrantLock();
public synchronized updateA() {
daoLock.lock();
// Do stuff...
}
public synchronized updateB() {
daoLock.lock();
// Do stuff...
}
public synchronized updateC() {
daoLock.lock();
// Do stuff...
}
public synchronized getA() {
daoLock.lock();
// Do stuff...
}
public synchronized getB() {
daoLock.lock();
// Do stuff...
}
public synchronized getC() {
daoLock.lock();
// Do stuff...
}
}
我不确定解锁的位置。如果我把它放在每个DAO类方法中,它会让其他线程不是吗?
这里有更好的解决方案吗?
答案 0 :(得分:3)
您正尝试在客户端同步对数据库的访问,这从根本上说是错误的地方。如果另一个客户在此期间写了一个怎么办?
最好将此类同步保留在数据库本身,使用事务(MySQL,PostgreSQL)。
即使您没有多个客户端也永远不会,使用事务是一个更好的解决方案。否则,你的所有线程都会被阻塞,即使它们只是在进行读取,这原则上可以同时发生。
答案 1 :(得分:1)
除了托马斯的好答案之外,还有另外一个值得关注的方面: interfaces 应该以一种易于做正确事情的方式编写;并且很难做错事。
含义:如果某些操作要求你按顺序调用a(),b(),c(),并采用“整体锁定方式”,那么:而不是在你的界面上有a,b,c,你提供完全一个方法abc()...获取锁,调用a,b,c并释放锁。
所以,你应该退后一步,从SOLID的角度看一下你班级的界面;或者更具体 - 从事物的“单一责任原则”方面考虑它。
换句话说:拥有一个类,它提供了许多完全“分离”的方法;其中一些甚至需要“以非常特殊的方式一起使用”,这是一种清晰的设计气味;所以另一个迹象表明你最好退一步看看这个设计。