写这篇博文的背景,是发生在前段时间的评教系统,评教系统出现瘫痪,为了找出问题,大家加班加点,找出的问题就是一个字:“锁”,由于评教系统会频繁的出现学生对数据库的查询,修改,查询,修改,这样就产生了一个进程资源不够,产生死锁!
在进行DRP项目中,id生成器的原理与我原先评教系统的机制是大致相同的,id加1,然后接着查询id,反复进行此操作,如果一个人,小数据量的在进行,系统不会报错,但是,米老师一直提出“大数据”,我们做出的软件不是一个人在使用。如何避免这样的问题。看下面的代码:
package com.bjpowernode.drp.util; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * id生成器 * @author Administrator * */ public class IdGenerator { /** * 根据表名生成该表的序列 * @param tableName * @return 返回生成的序列 */ <span style="color:#ff0000;">//public static synchronized int generate(String tableName) { //public synchronized int generate(String tableName) { //synchronized(this) {</span> public static int generate(String tableName) { //使用数据库的悲观锁for update <span style="color:#ff0000;">String sql = "select value from t_table_id where table_name=? for update";</span> Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; int value = 0; try { conn = DbUtil.getConnection(); //开始事务 DbUtil.beginTransaction(conn); pstmt = conn.prepareStatement(sql); pstmt.setString(1, tableName); rs = pstmt.executeQuery(); if (!rs.next()) { throw new RuntimeException(); } value = rs.getInt("value"); value++; //自加 modifyValueField(conn, tableName, value); //提交事务 DbUtil.commitTransaction(conn); }catch(Exception e) { e.printStackTrace(); //回滚事务 DbUtil.rollbackTransaction(conn); throw new RuntimeException(); }finally { DbUtil.close(rs); DbUtil.close(pstmt); DbUtil.resetConnection(conn); //重置Connection的状态 DbUtil.close(conn); } return value; } /** * 根据表名更新序列字段的值 * @param conn * @param tableName * @param value */ private static void modifyValueField(Connection conn, String tableName, int value) throws SQLException { String sql = "update t_table_id set value=? where table_name=?"; PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement(sql); pstmt.setInt(1, value); pstmt.setString(2, tableName); pstmt.executeUpdate(); }finally { DbUtil.close(pstmt); } } public static void main(String[] args) { int retValue = IdGenerator.generate("t_client"); System.out.println(retValue); } }
请看上面代码中红色部分,static synchronized与synchronized以及synchronized(this)的区别(如果大家想看详细的介绍请看柳波师哥的博客点击打开链接):
1.synchronized static是某个类的范围,synchronized static 防止多个线程同时访问这个 类中的synchronized static 方法。它可以对类的所有对象实例起作用。 synchronized 是某实例的范围,synchronized 防止多个线程同时访问这个实例中的synchronized 方法。
2.synchronized方法与synchronized(this)代码快的区别
synchronized methods(){} 与synchronized(this){}之间没有什么区别,只是synchronized methods(){} 便于阅读理解,而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。
3.synchronized关键字是不能继承的
这里我想说一下关于死锁出现的情况以及解决的方案,大家看我的代码中红色的查询语句,
我在cmd窗口中实验了一下:
回车以后是没有提交数据的!
在另一个cmd窗口中,看看在红色区域是没有任何数据的!
出现上面的原因是在第一个窗口中锁住了数据库
那么第二个cmd窗口如何访问数据呢,在第一个窗口中提交事务或者回滚实务如下图:
当提交完成后在第二个窗口中就会自动出现下图:
上面在查询语句中加入了一个for update 这叫做悲观锁。
锁的概念在软考,操作系统,进程,线程和我们最近的评教系统中,都运用到了,如果将来以后做大数据,我相信锁的运用更是必不可少的!