以下是兩個表及其實體類。休眠與sqlserver死鎖問題
tbl_rules
| rule_id | rule_name |
@Entity
@Table(name = "db_user_name.tbl_rules")
public class Rule implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@GenericGenerator(name = "incre", strategy = "increment")
@GeneratedValue(generator = "incre")
@Column(name = "rule_id", unique = true, nullable = false)
private long ruleId;
@Column(name = "rule_name", length = 250)
private String ruleName;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "rules")
private Set<Benchmark> benchmarks = new HashSet<Benchmark>(0);
... getters and setters
}
tbl_benchmark
| benchmark_id | rule_id |
@Entity
@Table(name = "tbl_benchmark", catalog = "db_user_name")
@DynamicUpdate(value = true)
public class Benchmark implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "benchmark_id", unique = true, nullable = false)
private Long benchmarkId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rule_id", nullable = false)
private Rule rules;
.. getter and setters
}
在以下情況下
HibernateSessionManager.beginTransaction()
面對與sql server db
僵局問題;- 呼叫
saveRule(rule)
//在後端規則和基準兩個表 被鎖定(使用SQL Server鎖定表查詢) - 呼叫
saveBenchmark(benchmark)
//死鎖在此方法 HibernateSessionManager.commit()
;
代碼,其中死鎖發生:
HibernateSessionManager.beginTransaction();
UserIdManager.setCurrentGroupId(2);
if (savingObjects.get(AmlConstants.USERCREDENTAILS_STRING) != null){
userCredentials = (UserCredentials) savingObjects.get(AmlConstants.USERCREDENTAILS_STRING);
Util.setAuditLogField(AmlConstants.USERIDSTRING);
this.getAmlDAOFactory().getUserCredentialsDAO().updateUserDetails(userCredentials);
if (savingObjects.get(AmlConstants.USERBRANCHMAPPING_STRING) != null){
userBranchMapping = (UserBranchMapping) savingObjects.get(AmlConstants.USERBRANCHMAPPING_STRING);
Util.setAuditLogField(AmlConstants.BRANCH_STRING);
this.getAmlDAOFactory().getUserBranchMappingDAO().saveUserBranchMapping(userBranchMapping);
}
}
HibernateSessionManager.commit();
saveRule:
@Override
public Rule saveRule(Rule rule) throws Exception {
try {
getSession().saveOrUpdate(rule);
getSession().flush();
} catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
return rule;
}
saveBenchmark:
@Override
public Benchmark saveBenchMark(Benchmark benchmark) throws Exception {
try {
if (benchmark.getBenchmarkId() == null)
benchmark.setBenchmarkId(getBenchmarkCount() + 1);
getSession().clear();
getSession().saveOrUpdate(benchmark);
getSession().flush();
} catch (RuntimeException e) {
// logger.error("Runtime error while saving benchmark", e);
e.printStackTrace();
} catch (Exception e) {
logger.error("Exception while saving benchmark " + e.getMessage(), e);
}
return benchmark;
}
春季型流感嗜血桿菌CONFG文件:
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
..
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">com.aml.hibernate.SQLServerCustomeDialect</prop>
<prop key="hibernate.character_encoding">UTF-8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.generate_statistics">false</prop>
</props>
</property>
..
HibernateSessionManager.java
public class HibernateSessionManager {
public static Logger logger = Logger.getLogger(HibernateSessionManager.class);
public static final ThreadLocal<Session> currentSession = new ThreadLocal<Session>();
public static final ThreadLocal<java.util.List<Session>> sessionList = new ThreadLocal<java.util.List<Session>>();
/** Store transaction object on thread local
* this helps to make a request processing transactional */
public static final ThreadLocal<Transaction> transaction = new ThreadLocal<Transaction>();
public static final ThreadLocal<Map<String, Transaction>> transactionMap = new ThreadLocal<Map<String, Transaction>>();
/** keep the beginner method path which helps to commit on the same method only
* we are not supposed to make nested commits under a single request */
public static final ThreadLocal<String> callerXPath = new ThreadLocal<String>();
/**
* Returns existing hibernate session binded with current request thread,
* if no session already bind with current thread then it will open a new session, bind to current thread
* and returns the session object
*
* @param sessionFactory
* @return
* @throws HibernateException
*/
public static Session currentSession(SessionFactory sessionFactory) throws HibernateException {
Session s = (Session) currentSession.get();
// Open a new Session, if this Thread has none yet
if (s == null || !s.isOpen())
{
s = sessionFactory.openSession();
currentSession.set(s);
if(sessionList.get()==null)
sessionList.set(new LinkedList<Session>());
sessionList.get().add(s);
logger.debug("Opened new session:"+currentSession.get().hashCode());
}else{
logger.debug("returning existing session:"+currentSession.get().hashCode());
}
return s;
}
/**
* Closes all the sessions binded with current request thread
* @throws HibernateException
*/
public static void closeSession() throws HibernateException {
currentSession.set(null);
transaction.set(null);
callerXPath.set(null);
try{
if(sessionList.get()!=null)
for (int i = 0; i < sessionList.get().size(); i++) {
Session s = sessionList.get().get(i);
try{
if (s != null && s.isOpen())
s.close();
logger.debug("Closed session - session local:"+ (s!=null?s.hashCode(): ""));
}catch (Exception e) { logger.debug("Error while closing session: ", e); }
}
transactionMap.get().clear();
}catch (Exception e) { logger.debug("Error while closing session: ", e); }
sessionList.set(null);
transactionMap.set(null);
}
// ------------------- Transaction management ------------------
/**
* Starts a new hibernate transaction on the session binded to current request thread
* if there is already a transaction started on this thread, ignores creation of another transaction
* all the db calls on a single request thread has to come under a single transaction
* @return
*/
public static boolean beginTransaction(){
try{
logger.debug("beginTransaction............... ");
Transaction t = transaction.get();
if(t == null && callerXPath.get()==null){
Session s = currentSession.get();
t = s.beginTransaction();
t.registerSynchronization(new Synchronization() {
@Override
public void beforeCompletion() {
logger.debug("Transaction-beforeCompletion............... ");
}
@Override
public void afterCompletion(int status) {
logger.debug("Transaction-afterCompletion............... "+status);
}
});
transaction.set(t);
callerXPath.set(getCallerMethodInvolvedinTransaction());
if(transactionMap.get()==null)
transactionMap.set(new HashMap<String, Transaction>());
transactionMap.get().put(callerXPath.get(), t);
logger.debug("Started new hibernate transaction:"+t);
}
}catch (Exception e) {
logger.error("Error while starting new transaction: ", e);
return false;
}
return true;
}
/**
* if we already have a hibernate transaction created on the current request thread and some thing is committed on it
* it will rollback the changes done after the transaction initialization
*/
public static void rollback(){
try{
Transaction t = transactionMap.get().get(callerXPath.get());
if(t != null){
t.rollback();
logger.debug("Roll back success on transaction:"+t);
}
}catch (Exception e) {
logger.error("Exception while trying to rollback", e);
}
}
/**
* Commits all the changes done after the transaction started on the current request thread
* this accepts the commit command from the only method which started the transaction
* This will unlink the current session and then currentSession() method can give another session as existing one is unlinked on the thread local
*/
public static void commit(){
try{
logger.debug("commit............... ");
Transaction t = transaction.get();
if(t != null /*&& !t.wasCommitted()*/
&& callerXPath.get()!=null && callerXPath.get().equals(getCallerMethodInvolvedinTransaction())){
t.commit();
currentSession.get().clear();
currentSession.set(null);
transaction.set(null);
callerXPath.set(null);
logger.debug("Commit success on transaction:"+t);
}
}catch (Exception e) {
logger.error("Exception while trying to commit", e);
}
}
/**
* get the caller method xpath: <package>.<classname>.<methodname>
* @return
*/
public static String getCallerMethodInvolvedinTransaction() {
try{
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
return stElements[3].toString().split("\\(")[0];
/*for (int i = 3; i < stElements.length; i++) {
String rawFQN = stElements[i].toString().split("\\(")[0];
String className = rawFQN.substring(0, rawFQN.lastIndexOf('.'));
String methodName = rawFQN.substring(rawFQN.lastIndexOf('.')+1);
Object carObj = Class.forName(className).newInstance();
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(className);
CtMethod methodX = cc.getDeclaredMethod(methodName);
int xlineNumber = methodX.getMethodInfo().getLineNumber(0);
Method method = carObj.getClass().getMethod(methodName);
if (method.isAnnotationPresent(JCTransaction.class))
{
return rawFQN;
}
}*/
}catch (Exception e) {
logger.error("" , e);
}
return null;
}
}
但同樣工作的罰款與oracle db
(與Oracle HIB屬性)。
提供死鎖圖(可從SQL SQL system_health擴展事件會話中獲得),執行計劃和表DDL。 –
您沒有提供任何死鎖證據,包括任何顯示死鎖正在發生的錯誤消息,堆棧跟蹤或日誌輸出。如果沒有更多信息,任何人都不可能幫助你。 –
@JimGarrison,在這個階段我沒有收到任何錯誤,因爲基準表被鎖定(從數據庫觀察),所以服務器很簡單。在此之後,我只是重新啓動服務器。我已經通過添加Hibernate會話管理器類 – TSKSwamy