事务的四种特性

    技术2022-07-10  151

    一 什么是事务 数据库事务是指作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部执行,要么全部不执行。 为什么需要事务 经典的银行转账行为,A账户转给B账户10元,数据库操作需要两步,第一步A账户减10元,第二步B账户加10元,如果没有事务并且在两步中间发生异常,就会导致A的账户少了10元,但B的账户没有变化,如果不能保证这两步操作统一,银行的转账业务也没法进行展开了。 事务管理是每个数据库(oracle、mysql、db等)都必须实现的。 二 事务的四大特性 原子性 (atomicity):强调事务的不可分割. 一致性 (consistency):事务的执行的前后数据的完整性保持一致. 隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰 持久性(durability) :事务一旦结束,数据就持久到数据库 事务运行模式(3种)

    自动提交事务:默认事务管理模式。如果一个语句成功地完成,则提交该语句;如果遇到错误,则回滚该语句。 显式事务:以BEGIN TRANSACTION显式开始,以COMMIT或ROLLBACK显式结束。 隐性事务:当连接以此模式进行操作时,sql将在提交或回滚当前事务后自动启动新事务。无须描述事务的开始,只需提交或回滚每个事务。它生成连续的事务链。 下面做一个事务的示例: JDBC用了Druid连接池 1、maven引包

    <!--mysql驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency>

    1 2 3 4 5 6 7 8 9 10 11 12 2、数据库设计

    CREATE TABLE account ( userid varchar(64) NOT NULL, username varchar(64) NOT NULL, accountbalance decimal(10,2) NOT NULL DEFAULT ‘0.00’, createtime datetime DEFAULT NULL, updatetime datetime DEFAULT NULL, PRIMARY KEY (userid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    INSERT INTO account VALUES (‘1001’, ‘张三’, ‘1000.00’, ‘2018-11-09 09:39:52’, ‘2018-11-09 09:39:55’);

    INSERT INTO account VALUES (‘1002’, ‘李四’, ‘1000.00’, ‘2018-11-09 09:40:12’, ‘2018-11-09 09:40:14’);

    3、建立jdbc.properties

    driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/zhd?useUnicode=true&characterEncoding=UTF-8&InnoDB=true&useSSL=false username=root password=123456 1 2 3 4 4、建立连接池工具类DBPoolConnection

    import java.io.InputStream; import java.sql.SQLException; import java.util.Properties;

    import org.slf4j.Logger; import org.slf4j.LoggerFactory;

    import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import com.alibaba.druid.pool.DruidPooledConnection;

    public class DBPoolConnection { static Logger log = LoggerFactory.getLogger(DBPoolConnection.class); private static DBPoolConnection dbPoolConnection = null; private static DruidDataSource druidDataSource = null;

    static { Properties properties = loadPropertiesFile("jdbc.properties"); try { druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); // DruidDataSrouce工厂模式 } catch (Exception e) { log.error("获取配置失败"); } } /** * @param string 配置文件名 * @return Properties对象 */ private static Properties loadPropertiesFile(String fullFile) { if (null == fullFile || fullFile.equals("")) { throw new IllegalArgumentException("Properties file path can not be null" + fullFile); } InputStream inputStream = null; Properties p = null; try { ClassLoader cl = DBPoolConnection.class.getClassLoader(); inputStream = cl.getResourceAsStream(fullFile); p = new Properties(); p.load(inputStream); } catch (Exception e) { e.printStackTrace(); } finally { try { if (null != inputStream) { inputStream.close(); } } catch (Exception e) { e.printStackTrace(); } } return p; } /** * 数据库连接池单例 * * @return */ public static synchronized DBPoolConnection getInstance() { if (null == dbPoolConnection) { dbPoolConnection = new DBPoolConnection(); } return dbPoolConnection; } /** * 返回druid数据库连接 * * @return * @throws SQLException */ public DruidPooledConnection getConnection() throws SQLException { return druidDataSource.getConnection(); }

    } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5、建立JDBCUtil工具类

    import java.lang.reflect.Field; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;

    import org.slf4j.Logger; import org.slf4j.LoggerFactory;

    /**

    对jdbc的完整封装

    */ public class JDBCUtil {

    public static Logger log = LoggerFactory.getLogger(JDBCUtil.class); /** * insert update delete SQL语句的执行的统一方法 * * @param sql SQL语句 * @param params 参数数组,若没有参数则为null * @return 受影响的行数 */ public int executeUpdate(String sql, Object... params) { // 受影响的行数 int affectedLine = 0; // 创建ResultSetMetaData对象 Connection conn = null; PreparedStatement pst = null; try { // 获得连接 conn = DBPoolConnection.getInstance().getConnection(); // 调用SQL pst = conn.prepareStatement(sql); // 参数赋值 if (params != null) { for (int i = 0; i < params.length; i++) { pst.setObject(i + 1, params[i]); } } /* * 在此 PreparedStatement 对象中执行 SQL 语句, 该语句必须是一个 SQL 数据操作语言(Data * Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE * 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。 */ // 执行 affectedLine = pst.executeUpdate(); } catch (SQLException e) { System.out.println(e.getMessage()); } finally { // 释放资源 closeAll(conn, pst, null); } return affectedLine; } /** * insert update delete SQL语句的执行的统一方法 * * @param sql SQL语句 * @param params 参数数组,若没有参数则为null * @return 受影响的行数 */ public int executeUpdate(Connection conn, String sql, Object... params) { // 受影响的行数 int affectedLine = 0; // 创建ResultSetMetaData对象 PreparedStatement pst = null; try { // 获得连接 // 调用SQL pst = conn.prepareStatement(sql); // 参数赋值 if (params != null) { for (int i = 0; i < params.length; i++) { pst.setObject(i + 1, params[i]); } } /* * 在此 PreparedStatement 对象中执行 SQL 语句, 该语句必须是一个 SQL 数据操作语言(Data * Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE * 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。 */ // 执行 affectedLine = pst.executeUpdate(); } catch (SQLException e) { System.out.println(e.getMessage()); } finally { // 释放资源 close(pst); } return affectedLine; } /** * 获取结果集,并将结果放在List中 * * @param sql SQL语句 params 参数,没有则为null * @return List 结果集 */ public List<Map<String, Object>> excuteQuery(String sql, Object... params) { // 创建ResultSetMetaData对象 ResultSetMetaData rsmd = null; Connection conn = null; PreparedStatement pst = null; ResultSet rst = null; // 创建List List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); try { conn = DBPoolConnection.getInstance().getConnection(); // 调用SQL pst = conn.prepareStatement(sql); // 参数赋值 if (params != null) { for (int i = 0; i < params.length; i++) { pst.setObject(i + 1, params[i]); } } // 执行 rst = pst.executeQuery(); rsmd = rst.getMetaData(); // 获得结果集列数 int columnCount = rsmd.getColumnCount(); // 将ResultSet的结果保存到List中 while (rst.next()) { Map<String, Object> map = new HashMap<String, Object>(); for (int i = 1; i <= columnCount; i++) { map.put(rsmd.getColumnLabel(i), rst.getObject(i)); } list.add(map);// 每一个map代表一条记录,把所有记录存在list中 } } catch (SQLException e1) { System.out.println(e1.getMessage()); } finally { // 关闭所有资源 closeAll(conn, pst, rst); } return list; } /** * 关闭所有资源 */ private void closeAll(Connection conn, PreparedStatement pst, ResultSet rst) { // 关闭结果集对象 if (rst != null) { try { rst.close(); } catch (SQLException e) { System.out.println(e.getMessage()); } } // 关闭PreparedStatement对象 if (pst != null) { try { pst.close(); } catch (SQLException e) { System.out.println(e.getMessage()); } } // 关闭Connection 对象 if (conn != null) { try { conn.close(); } catch (SQLException e) { System.out.println(e.getMessage()); } } } /** * 关闭所有资源 */ public void close(AutoCloseable autoCloseable) { if (autoCloseable != null) { try { autoCloseable.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } } /** * 通过反射机制查询单条记录 * * @param sql * @param params * @param cls * @return * @throws Exception */ public <T> T findSimpleRefResult(String sql, Class<T> cls, Object... params) { T resultObject = null; int index = 1; Connection conn = null; PreparedStatement pst = null; ResultSet rst = null; try { conn = DBPoolConnection.getInstance().getConnection(); pst = conn.prepareStatement(sql); if (params != null) { for (int i = 0; i < params.length; i++) { pst.setObject(index++, params[i]); } } rst = pst.executeQuery(); ResultSetMetaData metaData = rst.getMetaData(); int cols_len = metaData.getColumnCount(); while (rst.next()) { // 通过反射机制创建一个实例 resultObject = cls.newInstance(); for (int i = 0; i < cols_len; i++) { String cols_name = metaData.getColumnName(i + 1); Object cols_value = rst.getObject(cols_name); if (cols_value == null) { cols_value = ""; } try { Field field = cls.getDeclaredField(cols_name.toLowerCase()); field.setAccessible(true); // 打开javabean的访问权限 field.set(resultObject, cols_value); } catch (Exception e) { e.printStackTrace(); } } } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pst, rst); } return resultObject; } /** * 通过反射机制查询多条记录 * * @param sql * @param params * @param cls * @return * @throws Exception */ public <T> List<T> findMoreRefResult(String sql, Class<T> cls, Object... params) { List<T> list = new ArrayList<T>(); int index = 1; Connection connection = null; PreparedStatement pstmt = null; ResultSet resultSet = null; try { connection = DBPoolConnection.getInstance().getConnection(); pstmt = connection.prepareStatement(sql); if (params != null) { for (int i = 0; i < params.length; i++) { pstmt.setObject(index++, params[i]); } } resultSet = pstmt.executeQuery(); ResultSetMetaData metaData = resultSet.getMetaData(); int cols_len = metaData.getColumnCount(); while (resultSet.next()) { // 通过反射机制创建一个实例 T resultObject = cls.newInstance(); for (int i = 0; i < cols_len; i++) { String cols_name = metaData.getColumnName(i + 1); Object cols_value = resultSet.getObject(cols_name); if (cols_value == null) { cols_value = ""; } try { Field field = cls.getDeclaredField(cols_name.toLowerCase()); field.setAccessible(true); // 打开javabean的访问权限 field.set(resultObject, cols_value); } catch (Exception e) { e.printStackTrace(); } } list.add(resultObject); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(connection, pstmt, resultSet); } return list; } /** * 通过反射机制查询多条记录 * * @param sql * @param params * @param cls * @return * @throws Exception */ public List<String> findMoreRefResult(String sql, Object... params) { List<String> list = new ArrayList<String>(); int index = 1; Connection connection = null; PreparedStatement pstmt = null; ResultSet resultSet = null; try { connection = DBPoolConnection.getInstance().getConnection(); pstmt = connection.prepareStatement(sql); if (params != null) { for (int i = 0; i < params.length; i++) { pstmt.setObject(index++, params[i]); } } resultSet = pstmt.executeQuery(); while (resultSet.next()) { // 通过反射机制创建一个实例 String cols_value = resultSet.getString(1); list.add(cols_value); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(connection, pstmt, resultSet); } return list; } /** * SQL 查询将查询结果:一行一列 * * @param sql SQL语句 * @param params 参数数组,若没有参数则为null * @return 结果集 */ public Object executeQuerySingle(String sql, Object... params) { Connection conn = null; PreparedStatement pst = null; ResultSet rst = null; Object object = null; try { // 获得连接 conn = DBPoolConnection.getInstance().getConnection(); // 调用SQL pst = conn.prepareStatement(sql); // 参数赋值 if (params != null) { for (int i = 0; i < params.length; i++) { pst.setObject(i + 1, params[i]); } } // 执行 rst = pst.executeQuery(); if (rst.next()) { object = rst.getObject(1); } } catch (SQLException e) { e.printStackTrace(); } finally { closeAll(conn, pst, rst); } return object; }

    } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 5、进行测试:

    正常情况下:

    public class JDBCTest { public static void main(String[] args) { JDBCUtil jdbcUtil = new JDBCUtil(); Connection conn = null; try { conn = DBPoolConnection.getInstance().getConnection(); conn.setAutoCommit(false); String sql_1 = “update account set accountbalance = accountbalance + ? where userid = ?”; String sql_2 = “update account set accountbalance = accountbalance - ? where userid = ?”; int line_1 = jdbcUtil.executeUpdate(conn, sql_1, 10, “1001”); int line_2 = jdbcUtil.executeUpdate(conn, sql_2, 10, “1002”); conn.commit(); } catch (SQLException e) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } finally { jdbcUtil.close(conn); } } } 异常情况下:

    public class JDBCTest { public static void main(String[] args) { JDBCUtil jdbcUtil = new JDBCUtil(); Connection conn = null; try { conn = DBPoolConnection.getInstance().getConnection(); conn.setAutoCommit(false); String sql_1 = “update account set accountbalance = accountbalance + ? where userid = ?”; String sql_2 = “update account set accountbalance = accountbalance - ? where userid = ?”; int line_1 = jdbcUtil.executeUpdate(conn, sql_1, 10, “1001”); if (line_1 == 1) { throw new RuntimeException(); } int line_2 = jdbcUtil.executeUpdate(conn, sql_2, 10, “1002”); conn.commit(); } catch (SQLException e) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } finally { jdbcUtil.close(conn); } } }

    Processed: 0.016, SQL: 9