Connection con=super.getCon();
PreparedStatement ps=null;
ResultSet rs=null;
String sql="insert into z_udk (name,sex,age) values ('na',0,12)";
int i=0;
final Lock lock = new ReentrantLock(true);
try{
lock.lock();
ps=con.prepareStatement(sql);
ps.executeUpdate();
ps=con.prepareStatement("select max(id) from z_udk");
rs=ps.executeQuery();
while(rs.next()){
i=rs.getInt(1);
}
}finally{
super.closeAll(con, ps, rs);
lock.unlock();
return i;
}
}
上述代码先插入一条语句,然后再执行查询操作,获取到结果后,再执行关闭数据库连接,最后释放锁,返回结果。
下面是执行语句:
final Test dao=new Test();
Thread d=new Thread(new Runnable(){
public void run(){
try {
System.out.println(dao.selectId());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread d1=new Thread(new Runnable(){
public void run(){
try {
System.out.println(dao.selectId());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread d2=new Thread(new Runnable(){
public void run(){
try {
System.out.println(dao.selectId());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
d.start();
d1.start();
d2.start();
}
执行上述代码后,多线程三次插入数据,但查询结果多次与数据库结果不一致,三次打印的id多半时间都是同一个id值。查询数据库后,发现已经插入了三条数据。打印的id多半时候都是最后一条数据的id。这又是为什么呢?
将代码改为:
final Test dao=new Test();
try {
System.out.println(dao.selectAll());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println(dao.selectAll());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println(dao.selectAll());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
结果为插入三条数据,打印的id与数据库的一致,三个不同值的id。
final Test dao=new Test();
ReentrantLock是一个可重入的互斥锁,重入锁是一种递归无阻塞的同步机制。ReentrantLock由最近成功获取锁,还没有释放的线程所拥有,当锁被另一个线程拥有时,调用lock的线程可以成功获取锁。
后来想到数据库打开一次连接,关闭一次连接都需要时间。在多线程连接的情况下,第一次插入数据,然后查询数据,数据库尚未来得及响应,第二次插入数据,查询数据的任务又来临了,接着是第三次,到第三次,最后数据库插入数据之后,查询到数据然后返回,此时自然是第三次插入之后的数据。如果第一次插入数据之后,然后查询数据在第二次操作来临之前执行完成,那么第一次的操作结果为打印刚插入的id与数据库一致。同理第二次的操作在第三次操作之前完成,结果也是与数据库一致。
但事实却是,数据库操作与多线程在不停竞争,很难保证想要的结果。
将代码改为:
public int selectId() throws ClassNotFoundException,SQLException{
synchronized(this){
Connection con=super.getCon();
PreparedStatement ps=null;
ResultSet rs=null;
String sql="insert into z_udk (name,sex,age) values ('na',0,12)";
int i=0;
try{
ps=con.prepareStatement(sql);
ps.executeUpdate();
ps=con.prepareStatement("select max(id) from z_udk");
rs=ps.executeQuery();
while(rs.next()){
i=rs.getInt(1);
}
}finally{
super.closeAll(con, ps, rs);
return i;
}
}
}
后,每次的操作与数据库一致。这是因为:当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。