线程同步--悲观锁

在做数据库访问的时候,遇到了这样的问题:两个线程同时访问同一对象中的方法,那么就可能会引发数据不一致的问题,那么我们需要做的,就是加上锁。


第一种方案:Synchronized


Java中用来给对象和方法或者代码加锁的当他锁定一个方法或者一个代码块的时候同一时刻最多只有一个线程执行该代码当两个并发线程访问同一个对象object中的这个加锁同步代码块时一个时间内只有一个线程得到另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块


用法:Synchronized 加入方法上和Synchronized(this)两种写法含义是一样的,都是对对象加锁。


实现方法:


<span style="font-size:18px;"><p>public staticsynchronized int  generatate(StringtableName){
		//使用数据库的悲观锁for update
		String sql ="select value from t_table_id where table_name=?";
		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);	
		}catch(SQLException e) {
			e.printStackTrace();		
		}finally {
			DbUtil.close(rs);
			DbUtil.close(pstmt);		
			DbUtil.close(conn);
		}
		return value;
	}
</p></span>

或者我们也可以这样写:


<span style="font-size:18px;">public synchronized int  generatate(String tableName){
		synchronized(this){</span>


第二种方案:悲观锁


可以使用数据库中的悲观锁,例如:select * from t_table_id where table_name? form update ,悲观锁是采用数据库机制实现的,数据被锁住之后,其他用户将无法查看,直到锁释放,只有提交或回滚事物锁才会释放。for update 语句只能放到 select 语句中,因为查询时把数据锁住才有意义。


我们封装数据回滚:


<span style="font-size:18px;">public static void beginTransaction(Connection conn){
	try{
		if(conn!= null){
			if(conn.getAutoCommit()){
				conn.setAutoCommit(false); //手动提交
			}
		}
	}catch(SQLException e){
		
	}
}
</span>

封装事物的提交:


<span style="font-size:18px;">public static void commitTransaction(Connection conn){
		try{
			if(conn!= null){
				if(!conn.getAutoCommit()){
					conn.commit();
				}
			}
		}catch(SQLException e){}
	}
</span>

封装事物回滚:


<span style="font-size:18px;">public static void rollbackTracsaction(Connection conn){
		try{
			if(conn!= null){
				if(!conn.getAutoCommit()){
					conn.rollback();
				}
			}
		}catch(SQLException e){}
	}
</span>

封装事物重置:


<span style="font-size:18px;">public static void ressetConnection(Connection conn){
		try{
			if(conn!= null){
				if(conn.getAutoCommit()){
					conn.setAutoCommit(false);
				}else
				{
					conn.setAutoCommit(true);
				}
			}
		}catch(SQLException e){}
	}
</span>


测试使用:


<span style="font-size:18px;">public static int  generatate(String tableName){
		//使用数据库的悲观锁for update
		String sql ="select value from t_table_id where table_name=? for update";
		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(SQLException e) {
			e.printStackTrace();
			//回滚事物
			DbUtil.rollbackTracsaction(conn);
		}finally {
			DbUtil.close(rs);
			DbUtil.close(pstmt);
			DbUtil.ressetConnection(conn);//充值到Connection的状态
			DbUtil.close(conn);
		}
		return value;
	}
</span>

总结:


数据库中的数据无价,悲观锁,有强烈的独占和排他的特性,对数据被外界修改保持保守态度.在这个数据处理过程,将数据处于锁定状态,这就是悲观锁的实现.


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值