在只读事务与普通读 work log 中假设了一种死锁,非mysql死锁,而是jvm死锁
CREATE TABLE `mytest` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; LOCK TABLES `mytest` WRITE; /*!40000 ALTER TABLE `mytest` DISABLE KEYS */; INSERT INTO `mytest` (`id`, `name`) VALUES (1,‘db‘);
public class JdbcUtilDeadLock {
private static final String URL_NO_TIMEZONE="jdbc:mysql://127.0.0.1:53306/mytest?useUnicode=true&characterEncoding=utf-8&useSSL=false";
private static final String USER="root";
private static final String PASSWORD="";
public static void main(String []f) {
select();
}
/**
* 这个不用开启事务
* @return
*/
public static List<Map<String,Object>> update() {
Connection conn = null;
List<Map<String,Object>> list = new ArrayList<>();
try{
conn = DriverManager.getConnection(URL_NO_TIMEZONE, USER, PASSWORD);
PreparedStatement pstmt = conn.prepareStatement("update mytest set `name` = ‘db‘ where id = 1");
pstmt.executeUpdate();
} catch (Exception e){
e.printStackTrace();
}
return list;
}
/**
* 开启事务后 update阻塞
* @return
*/
public static List<Map<String,Object>> select() {
Connection conn = null;
ResultSet rs = null;
List<Map<String,Object>> list = new ArrayList<>();
try{
conn = DriverManager.getConnection(URL_NO_TIMEZONE, USER, PASSWORD);
conn.setAutoCommit(false);
/**
* 如果不开启事务,则不会死锁
*/
// conn.setAutoCommit(true);
PreparedStatement pstmt = conn.prepareStatement("select * from mytest where id = 1 for update");
rs = pstmt.executeQuery();
ResultSetMetaData md = rs.getMetaData(); //获得结果集结构信息,元数据
int columnCount = md.getColumnCount(); //获得列数
while (rs.next()) {
Map<String,Object> rowData = new HashMap<String,Object>();
for (int i = 1; i <= columnCount; i++) {
rowData.put(md.getColumnLabel(i), rs.getObject(i));
}
list.add(rowData);
}
/**
* 阻塞死锁
*/
update();
if(!conn.getAutoCommit())
conn.commit();
System.out.println(list);
} catch (Exception e){
e.printStackTrace();
try {
if(!conn.getAutoCommit())
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
return list;
}
}
java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
[{name=db, id=1}]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1086)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4237)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4169)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2617)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2834)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2156)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2441)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2366)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2350)
at jdbctimezone.JdbcUtilDeadLock.update(JdbcUtilDeadLock.java:32)
at jdbctimezone.JdbcUtilDeadLock.select(JdbcUtilDeadLock.java:73)
at jdbctimezone.JdbcUtilDeadLock.main(JdbcUtilDeadLock.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
阻塞时,使用jstack
"main" #1 prio=5 os_prio=31 tid=0x00007f962a800000 nid=0x1603 runnable [0x000070000ee89000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114)
at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161)
at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189)
- locked <0x0000000795f220b0> (a com.mysql.jdbc.util.ReadAheadInputStream)
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3163)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3620)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3609)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4160)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2617)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2834)
- locked <0x0000000795f18b28> (a com.mysql.jdbc.JDBC4Connection)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2156)
- locked <0x0000000795f18b28> (a com.mysql.jdbc.JDBC4Connection)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2441)
- locked <0x0000000795f18b28> (a com.mysql.jdbc.JDBC4Connection)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2366)
- locked <0x0000000795f18b28> (a com.mysql.jdbc.JDBC4Connection)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2350)
at jdbctimezone.JdbcUtilDeadLock.update(JdbcUtilDeadLock.java:32)
at jdbctimezone.JdbcUtilDeadLock.select(JdbcUtilDeadLock.java:73)
at jdbctimezone.JdbcUtilDeadLock.main(JdbcUtilDeadLock.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)