事务
概念
如果一个包含多个步骤的业务操作,被事务管理,要么同时成功,要么同时失败。
操作
- 开启事务:start transaction
 
- 回滚:rollback
 
- 提交:commit
 
在MySQL数据库中事务默认自动提交
- 一条DML(增删改)语句会自动提交一次事务。
 
- 事务提交的两种方式:
- 自动提交
 
- 手动提交:需要先开启事务,再提交(Oracle数据库默认手动提交事务)
 
 
- 修改事务的默认提交方式
- 查看事务的默认提交方式:SELECT @@autocommit
 
- 修改默认提交方式:set @@autocommit=0
 
 
事务的四大特性
- 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
 
- 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
 
- 隔离性:多个事务之间。相互独立。
 
- 一致性:事务操作前后数据总量不变。
 
事务的隔离级别
概念:多个事务之间是相互独立的。但是多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
存在问题:
- 脏读:一个事务,读取到另一个事务中没有提交的数据。
 
- 不可重复读:在同一个事务中,两次读取到的数据不一样。
 
- 幻读:一个事务操作(DML)数据表中所有的记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
 
隔离级别:
- read uncommitted:读未提交
 
- read committed:读已提交(Oracle)
 
- repeatable read:可重复读(MySQL默认)
 
- serializable:串行化
 
注意:隔离级别从小到大安全性越来越高,效率越来越低 
数据库查询隔离级别: select @@tx_isolation;
数据库设置隔离级别:set global transaction isolation level 级别字符串;
JDBC
概念
Java DataBase Connectivity Java数据库连接,Java语言操作数据库
JDBC本质:Sun公司定义了一套操作所有关系型数据库的规则(接口)。各个数据库厂商实现这套接口,提供数据库驱动jar包,我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
步骤
- 导入驱动jar包
 
- 注册驱动
 
- 获取数据库连接对象Connection
 
- 定义sql
 
- 获取执行sql语句的对象Statement
 
- 执行sql。接受返回结果
 
- 处理结果
 
- 释放资源
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | public static void main(String[] args) throws Exception {                  Class.forName("com.mysql.jdbc.Driver");                  Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/eesy", "root", "12345678");                  String sql = "update account set money = 20 where id = 1";                  Statement statement = conn.createStatement();         int count = statement.executeUpdate(sql);         System.out.println(count);                  statement.close();         conn.close();     }
  | 
 
详解各个对象
DriverManager:驱动管理对象
功能:
- 注册驱动:告诉程序该使用哪一个数据库jar包
- static void registerDriver(Driver driver):注册与给定的驱动程序。
 
- 我们使用Class.forName(“com.mysql.jdbc.Driver”)
 
- 通过静态代码块,使类被加载时,方法就被执行
 
- 5版本之后可以省略注册驱动的步骤
 
 
- 获取数据库连接:
- 参数:
- URL: 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
 
- user:用户名
 
- password:密码
 
 
- 如果连接的是本机的mysql服务器,并且mysql服务器默认端口是3306,则URL可以简写为:jdbc:mysql:///数据库名称
Connection:数据连接对象
功能: 
 
- 获取执行sql对象
- Statement createStatement()
 
- PreparedStatement prepareStatement(String sql)
 
 
- 管理事务:
- 开启事务:void setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务。
 
- 提交事务:void commit()
 
- 回滚事务:void rollback()
Statement:执行sql的对象
 
 
- 执行sql
- boolean execute(String sql):可以执行任意的sql
 
- int executeUpdate(String sql):执行DML(insert、update、delete)语句,DDL语句(create,alter、drop)语句。
 
- ResultSet executeQuery(String sql):执行DQL(select)语句。
ResultSet:结果集对象
用来封装查询的结果 
 
- next():游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
 
- getXxx(参数):获取数据,XXX代表数据类型,如 int getInt(),参数:
- int:代表列的编号,从1开始。
 
- String:代表列的名称
 
 
- 使用步骤:
- 游标向下移动一行
 
- 判断是否有数据
 
- 获取数据
PreparedStatement:执行sql的对象
SQL注入问题:在拼接sql时,有一些SQL关键字参与字符串的拼接,会造成安全性问题。 
 
例如用户随便输入密码,再加一句 OR ‘a’ = ‘a’,这就恒成立了
解决SQL注入问题:使用PreparedStatement对象来解决。
预编译的SQL:参数使用?作为占位符
- setString(1,”root”);
 
- setInt(2,12345678);
 
后期都会使用PrepareStatement对象,因为安全性和效率都更高。
抽取JBDBC工具类
目的:简化书写
分析:
- 抽取一个方法获取连接对象,通过配置文件
 
- 抽取一个方法释放资源
 
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
   | public class JDBCUtils {     private static String url;     private static String user;     private static String password;     private static String driver;          static {                  Properties pro = new Properties();         try {                          ClassLoader classLoader = JDBCUtils.class.getClassLoader();             URL resource = classLoader.getResource("jdbc.properties");             String path = resource.getPath();
              pro.load(new FileReader(path));             url = pro.getProperty("url");             password = pro.getProperty("password");             user = pro.getProperty("user");             driver = pro.getProperty("driver");             Class.forName(driver);         } catch (IOException | ClassNotFoundException e) {             e.printStackTrace();         }     }
      public static Connection getConnection() throws SQLException {         return DriverManager.getConnection(url,user,password);     }
      public static void close(Statement s,Connection conn){         if(s!=null){             try{                 s.close();             }catch(SQLException e){                 e.printStackTrace();             }         }
          if(conn!=null){             try{                 conn.close();             }catch(SQLException e){                 e.printStackTrace();             }         }     }
      public static void close(ResultSet rs,Statement s, Connection conn){
          if(rs!=null){             try{                 rs.close();             }catch(SQLException e){                 e.printStackTrace();             }         }
          if(s!=null){             try{                 s.close();             }catch(SQLException e){                 e.printStackTrace();             }         }
          if(conn!=null){             try{                 conn.close();             }catch(SQLException e){                 e.printStackTrace();             }         }     }
  }
  | 
 
数据库连接池
概念
其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户访问完之后,会讲连接对象归还给容器。
好处:
实现
标准接口:DataSource javax.sql包下的
方法:
- 获取连接:getConnection()
 
- 归还连接:如果连接对象Connection是从连接池中获取的,那么调用Connection.close()是归还连接,而不是关闭连接。
 
一般我们不去实现它,有数据库厂商来实现
- c3p0:较老
 
- Druid:数据库连接池实现技术,由阿里巴巴提供
 
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
   | public class JDBCUtils {     private static DataSource ds;
      static{         Properties pro = new Properties();         try {             pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));             ds = DruidDataSourceFactory.createDataSource(pro);         } catch (IOException e) {             e.printStackTrace();         }     }
      public static Connection getConnection() throws SQLException {         return ds.getConnection();     }
      public static void close(Statement stmt,Connection conn){         close(null,stmt,conn);     }
      public static void close(Resultset rs, Statement stmt, Connection conn){                  if(rs!=null){             try {                 rs.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }
 
          if(stmt!=null){             try {                 stmt.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }
          if(conn!=null){             try {                 conn.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }     }
      
 
      public static DataSource getDataSource(){         return ds;     } }
  | 
 
Spring JDBC
spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象来简化JDBC的框架。
步骤:
- 导入jar包
 
- 创建JDBCTemplate对象。依赖于数据源DataSource
- JdbcTemplate template = new jdbcTemplate(ds);
 
 
- 调用JdbcTemplate的方法来完成CRUD操作
- update():执行增删改语句
 
- queryForMap():查询结果,将结果集封装为Map集合
- 查询的结果集长度只能是1,将列名作为key,将值作为value,封装为Map。
 
 
- queryFoeList():查询结构将结果封装为List集合
 
- query():查询结构,将结果封装为JavaBean对象
 
- queryForObject():查询结果,将结果封装为对象
1 2 3 4 5 6 7 8 9 10 11 12
   | List<Emp> list = template.query(sql,new RowMapper<Emp>(){
      @Override     public Emp mapRow(Result rs,int i)throws SQLException{         Emp emp = new Emp();         int id = rs.getInt("id");         String name = rs.getString("name");         emp.setId(id);         emp.setName(name);         return emp;     } });
  | 
 
上面是自己写的实现类,也可以使用提供好的实现类1
   | List<Emp> list = template.query(sql,new BeanPropertyRowMapper<Emp>(Emp.class));
   | 
 
上面的一个问题在于,如果我们定义的类的属性是基本数据类型,就无法接收null,可以将属性的类型设置为引用类型,比如Integer。