JDBC核心技术(jdbc技术原理)

  本篇文章为你整理了JDBC核心技术(jdbc技术原理)的详细内容,包含有jdbc技术简介 jdbc技术原理 jdbc技术的特点 jdbc的核心api位于以下哪个包中 JDBC核心技术,希望能帮助你了解 JDBC核心技术。

  JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。

  不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。 ————面向接口编程

  1.5 JDBC程序编写步骤

  补充:ODBC(Open Database Connectivity,开放式数据库连接),是微软在Windows平台下推出的。使用者在程序中只需要调用ODBC API,由 ODBC 驱动程序将调用转换成为对特定的数据库的调用请求。

  第2章:获取数据库连接

  2.1 要素一:Driver接口实现类

  2.1.1 Driver接口介绍

  
加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名

  
通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例,因为 Driver 接口的驱动程序类都包含了静态代码块,在这个静态代码块中,会调用 DriverManager.registerDriver() 方法来注册自身的一个实例。下图是MySQL的Driver实现类的源码:

  
JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。

  
子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名

  
jdbc:mysql://localhost:3306/atguigu?useUnicode=true characterEncoding=utf8(如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)

  
try {

   //1.提供java.sql.Driver接口实现类的对象

   Driver driver = null;

   driver = new com.mysql.jdbc.Driver();

   //2.提供url,指明具体操作的数据

   String url = "jdbc:mysql://localhost:3306/test";

   //3.提供Properties的对象,指明用户名和密码

   Properties info = new Properties();

   info.setProperty("user", "root");

   info.setProperty("password", "abc123");

   //4.调用driver的connect(),获取连接

   Connection conn = driver.connect(url, info);

   System.out.println(conn);

   } catch (SQLException e) {

   e.printStackTrace();

   }

   }

 

 

  说明:上述代码中显式出现了第三方数据库的API

  2.4.2 连接方式二

  

 @Test

 

   public void testConnection2() {

   try {

   //1.实例化Driver

   String className = "com.mysql.jdbc.Driver";

   Class clazz = Class.forName(className);

   Driver driver = (Driver) clazz.newInstance();

   //2.提供url,指明具体操作的数据

   String url = "jdbc:mysql://localhost:3306/test";

   //3.提供Properties的对象,指明用户名和密码

   Properties info = new Properties();

   info.setProperty("user", "root");

   info.setProperty("password", "abc123");

   //4.调用driver的connect(),获取连接

   Connection conn = driver.connect(url, info);

   System.out.println(conn);

   } catch (Exception e) {

   e.printStackTrace();

   }

   }

 

  说明:相较于方式一,这里使用反射实例化Driver,不在代码中体现第三方数据库的API。体现了面向接口编程思想。

  2.4.3 连接方式三

  

 @Test

 

   public void testConnection3() {

   try {

   //1.数据库连接的4个基本要素:

   String url = "jdbc:mysql://localhost:3306/test";

   String user = "root";

   String password = "abc123";

   String driverName = "com.mysql.jdbc.Driver";

   //2.实例化Driver

   Class clazz = Class.forName(driverName);

   Driver driver = (Driver) clazz.newInstance();

   //3.注册驱动

   DriverManager.registerDriver(driver);

   //4.获取连接

   Connection conn = DriverManager.getConnection(url, user, password);

   System.out.println(conn);

   } catch (Exception e) {

   e.printStackTrace();

   }

   }

 

  说明:使用DriverManager实现数据库的连接。体会获取连接必要的4个基本要素。

  2.4.4 连接方式四

  

 @Test

 

   public void testConnection4() {

   try {

   //1.数据库连接的4个基本要素:

   String url = "jdbc:mysql://localhost:3306/test";

   String user = "root";

   String password = "abc123";

   String driverName = "com.mysql.jdbc.Driver";

   //2.加载驱动 (①实例化Driver ②注册驱动)

   Class.forName(driverName);

   //Driver driver = (Driver) clazz.newInstance();

   //3.注册驱动

   //DriverManager.registerDriver(driver);

   /*

   可以注释掉上述代码的原因,是因为在mysql的Driver类中声明有:

   static {

   try {

   DriverManager.registerDriver(new Driver());

   } catch (SQLException var1) {

   throw new RuntimeException("Cant register driver!");

   }

   }

   */

   //3.获取连接

   Connection conn = DriverManager.getConnection(url, user, password);

   System.out.println(conn);

   } catch (Exception e) {

   e.printStackTrace();

   }

   }

 

  说明:不必显式的注册驱动了。因为在DriverManager的源码中已经存在静态代码块,实现了驱动的注册。

  2.4.5 连接方式五(最终版)

  

 @Test

 

   public void testConnection5() throws Exception {

   //1.加载配置文件

   InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");

   Properties pros = new Properties();

   pros.load(is);

  

   //2.读取配置信息

   String user = pros.getProperty("user");

   String password = pros.getProperty("password");

   String url = pros.getProperty("url");

   String driverClass = pros.getProperty("driverClass");

   //3.加载驱动

   Class.forName(driverClass);

   //4.获取连接

   Connection conn = DriverManager.getConnection(url,user,password);

   System.out.println(conn);

   }

 

  其中,配置文件声明在工程的src目录下:【jdbc.properties】

  

user=root

 

  password=abc123

  url=jdbc:mysql://localhost:3306/test

  driver >

  说明:使用配置文件的方式保存配置信息,在代码中加载配置文件

  使用配置文件的好处:

  ①实现了代码和数据的分离,如果需要修改配置信息,直接在配置文件中修改,不需要深入代码 ②如果修改了配置信息,省去重新编译的过程。

  第3章:使用PreparedStatement实现CRUD操作

  3.1 操作和访问数据库

  
数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。

  
PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。

  
通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。

  
Statement 接口中定义了下列方法用于执行 SQL 语句:

  

int excuteUpdate(String sql):执行更新操作INSERT、UPDATE、DELETE

 

  ResultSet executeQuery(String sql):执行查询操作SELECT

 

  
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=a OR 1 = AND password = OR 1 = 1) ,从而利用系统的 SQL 引擎完成恶意行为的做法。

  
对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。

  
// SELECT user,password FROM user_table WHERE USER = 1 or AND PASSWORD = =1 or 1 = 1;

   String sql = "SELECT user,password FROM user_table WHERE USER = " + userName + " AND PASSWORD = " + password

   + "";

   User user = get(sql, User.class);

   if (user != null) {

   System.out.println("登陆成功!");

   } else {

   System.out.println("用户名或密码错误!");

   // 使用Statement实现对数据表的查询操作

   public T T get(String sql, Class T clazz) {

   T t = null;

   Connection conn = null;

   Statement st = null;

   ResultSet rs = null;

   try {

   // 1.加载配置文件

   InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");

   Properties pros = new Properties();

   pros.load(is);

   // 2.读取配置信息

   String user = pros.getProperty("user");

   String password = pros.getProperty("password");

   String url = pros.getProperty("url");

   String driverClass = pros.getProperty("driverClass");

   // 3.加载驱动

   Class.forName(driverClass);

   // 4.获取连接

   conn = DriverManager.getConnection(url, user, password);

   st = conn.createStatement();

   rs = st.executeQuery(sql);

   // 获取结果集的元数据

   ResultSetMetaData rsmd = rs.getMetaData();

   // 获取结果集的列数

   int columnCount = rsmd.getColumnCount();

   if (rs.next()) {

   t = clazz.newInstance();

   for (int i = 0; i columnCount; i++) {

   // //1. 获取列的名称

   // String columnName = rsmd.getColumnName(i+1);

   // 1. 获取列的别名

   String columnName = rsmd.getColumnLabel(i + 1);

   // 2. 根据列名获取对应数据表中的数据

   Object columnVal = rs.getObject(columnName);

   // 3. 将数据表中得到的数据,封装进对象

   Field field = clazz.getDeclaredField(columnName);

   field.setAccessible(true);

   field.set(t, columnVal);

   return t;

   } catch (Exception e) {

   e.printStackTrace();

   } finally {

   // 关闭资源

   if (rs != null) {

   try {

   rs.close();

   } catch (SQLException e) {

   e.printStackTrace();

   if (st != null) {

   try {

   st.close();

   } catch (SQLException e) {

   e.printStackTrace();

   if (conn != null) {

   try {

   conn.close();

   } catch (SQLException e) {

   e.printStackTrace();

   return null;

  }

 

  综上:

  3.3 PreparedStatement的使用

  3.3.1 PreparedStatement介绍

  
可以通过调用 Connection 对象的 preparedStatement(String sql) 方法获取 PreparedStatement 对象

  
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值

  
DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。

  
在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。

  
3.3.4 使用PreparedStatement实现增、删、改操作

  

 //通用的增、删、改操作(体现一:增、删、改 ; 体现二:针对于不同的表)

 

   public void update(String sql,Object ... args){

   Connection conn = null;

   PreparedStatement ps = null;

   try {

   //1.获取数据库的连接

   conn = JDBCUtils.getConnection();

   //2.获取PreparedStatement的实例 (或:预编译sql语句)

   ps = conn.prepareStatement(sql);

   //3.填充占位符

   for(int i = 0;i args.length;i++){

   ps.setObject(i + 1, args[i]);

   //4.执行sql语句

   ps.execute();

   } catch (Exception e) {

   e.printStackTrace();

   }finally{

   //5.关闭资源

   JDBCUtils.closeResource(conn, ps);

   }

 

  

  3.3.5 使用PreparedStatement实现查询操作

  

 // 通用的针对于不同表的查询:返回一个对象 (version 1.0)

 

   public T T getInstance(Class T clazz, String sql, Object... args) {

   Connection conn = null;

   PreparedStatement ps = null;

   ResultSet rs = null;

   try {

   // 1.获取数据库连接

   conn = JDBCUtils.getConnection();

   // 2.预编译sql语句,得到PreparedStatement对象

   ps = conn.prepareStatement(sql);

   // 3.填充占位符

   for (int i = 0; i args.length; i++) {

   ps.setObject(i + 1, args[i]);

   // 4.执行executeQuery(),得到结果集:ResultSet

   rs = ps.executeQuery();

   // 5.得到结果集的元数据:ResultSetMetaData

   ResultSetMetaData rsmd = rs.getMetaData();

   // 6.1通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值

   int columnCount = rsmd.getColumnCount();

   if (rs.next()) {

   T t = clazz.newInstance();

   for (int i = 0; i columnCount; i++) {// 遍历每一个列

   // 获取列值

   Object columnVal = rs.getObject(i + 1);

   // 获取列的别名:列的别名,使用类的属性名充当

   String columnLabel = rsmd.getColumnLabel(i + 1);

   // 6.2使用反射,给对象的相应属性赋值

   Field field = clazz.getDeclaredField(columnLabel);

   field.setAccessible(true);

   field.set(t, columnVal);

   return t;

   } catch (Exception e) {

   e.printStackTrace();

   } finally {

   // 7.关闭资源

   JDBCUtils.closeResource(conn, ps, rs);

   return null;

   }

 

  说明:使用PreparedStatement实现的查询操作可以替换Statement实现的查询操作,解决Statement拼串和SQL注入问题。

  3.4 ResultSet与ResultSetMetaData

  3.4.1 ResultSet

  
查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象

  
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现

  
ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的 hasNext() 和 next() 方法的结合体。

  
当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。

  
isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

  
 

  问题1:得到结果集后, 如何知道该结果集中有哪些列 ? 列名是什么?

   需要使用一个描述 ResultSet 的对象, 即 ResultSetMetaData

  问题2:关于ResultSetMetaData

  
获取 ResultSet 每一列的列的别名是什么:调用 ResultSetMetaData 的getColumnLabel() 方法

  
数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。

  
练习题1:从控制台向数据库的表customers中插入一条数据,表结构如下:

  

  练习题2:创立数据库表 examstudent,表结构如下:

  向数据表中添加如下数据:

  代码实现1:插入一个新的student 信息

  请输入考生的详细信息

  Type: IDCard: ExamCard: StudentName: Location: Grade:

  信息录入成功!

  代码实现2:在 eclipse中建立 java 程序:输入身份证号或准考证号可以查询到学生的基本信息。结果如下:

  代码实现3:完成学生信息的删除功能

  

  第4章 操作BLOB类型字段

  4.1 MySQL BLOB类型

  
MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。

  
插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的。

  
如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。

  
String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";

  PreparedStatement ps = conn.prepareStatement(sql);

  // 填充占位符

  ps.setString(1, "徐海强");

  ps.setString(2, "xhq@126.com");

  ps.setDate(3, new Date(new java.util.Date().getTime()));

  // 操作Blob类型的变量

  FileInputStream fis = new FileInputStream("xhq.png");

  ps.setBlob(4, fis);

  ps.execute();

  fis.close();

  JDBCUtils.closeResource(conn, ps);

 

 

  

  4.3 修改数据表中的Blob类型字段

  

Connection conn = JDBCUtils.getConnection();

 

  String sql = "update customers set photo = ? where id = ?";

  PreparedStatement ps = conn.prepareStatement(sql);

  // 填充占位符

  // 操作Blob类型的变量

  FileInputStream fis = new FileInputStream("coffee.png");

  ps.setBlob(1, fis);

  ps.setInt(2, 25);

  ps.execute();

  fis.close();

  JDBCUtils.closeResource(conn, ps);

 

  

  4.4 从数据表中读取大数据类型

  

String sql = "SELECT id, name, email, birth, photo FROM customer WHERE id = ?";

 

  conn = getConnection();

  ps = conn.prepareStatement(sql);

  ps.setInt(1, 8);

  rs = ps.executeQuery();

  if(rs.next()){

   Integer id = rs.getInt(1);

   String name = rs.getString(2);

   String email = rs.getString(3);

   Date birth = rs.getDate(4);

   Customer cust = new Customer(id, name, email, birth);

   System.out.println(cust);

   //读取Blob类型的字段

   Blob photo = rs.getBlob(5);

   InputStream is = photo.getBinaryStream();

   OutputStream os = new FileOutputStream("c.jpg");

   byte [] buffer = new byte[1024];

   int len = 0;

   while((len = is.read(buffer)) != -1){

   os.write(buffer, 0, len);

   JDBCUtils.closeResource(conn, ps, rs);

   if(is != null){

   is.close();

   if(os != null){

   os.close();

  }

 

  

  第5章 批量插入

  5.1 批量执行SQL语句

  当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率

  JDBC的批量处理语句包括下面三个方法:

  


Connection conn = JDBCUtils.getConnection();

 

  Statement st = conn.createStatement();

  for(int i = 1;i = 20000;i++){

   String sql = "insert into goods(name) values(name_ + "+ i +")";

   st.executeUpdate(sql);

  }

 

  

  5.2.2 实现层次二:使用PreparedStatement

  

long start = System.currentTimeMillis();

 

  Connection conn = JDBCUtils.getConnection();

  String sql = "insert into goods(name)values(?)";

  PreparedStatement ps = conn.prepareStatement(sql);

  for(int i = 1;i = 20000;i++){

   ps.setString(1, "name_" + i);

   ps.executeUpdate();

  long end = System.currentTimeMillis();

  System.out.println("花费的时间为:" + (end - start));//82340

  
* 修改1: 使用 addBatch() / executeBatch() / clearBatch()

   * 修改2:mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。

   * ?rewriteBatchedStatements=true 写在配置文件的url后面

   * 修改3:使用更新的mysql 驱动:mysql-connector-java-5.1.37-bin.jar

  @Test

  public void testInsert1() throws Exception{

   long start = System.currentTimeMillis();

   Connection conn = JDBCUtils.getConnection();

   String sql = "insert into goods(name)values(?)";

   PreparedStatement ps = conn.prepareStatement(sql);

   for(int i = 1;i = 1000000;i++){

   ps.setString(1, "name_" + i);

   //1.“攒”sql

   ps.addBatch();

   if(i % 500 == 0){

   //2.执行

   ps.executeBatch();

   //3.清空

   ps.clearBatch();

   long end = System.currentTimeMillis();

   System.out.println("花费的时间为:" + (end - start));//20000条:625 //1000000条:14733

   JDBCUtils.closeResource(conn, ps);

  }

 

  5.2.4 实现层次四

  

/*

 

  * 层次四:在层次三的基础上操作

  * 使用Connection 的 setAutoCommit(false) / commit()

  @Test

  public void testInsert2() throws Exception{

   long start = System.currentTimeMillis();

   Connection conn = JDBCUtils.getConnection();

   //1.设置为不自动提交数据

   conn.setAutoCommit(false);

   String sql = "insert into goods(name)values(?)";

   PreparedStatement ps = conn.prepareStatement(sql);

   for(int i = 1;i = 1000000;i++){

   ps.setString(1, "name_" + i);

   //1.“攒”sql

   ps.addBatch();

   if(i % 500 == 0){

   //2.执行

   ps.executeBatch();

   //3.清空

   ps.clearBatch();

   //2.提交数据

   conn.commit();

   long end = System.currentTimeMillis();

   System.out.println("花费的时间为:" + (end - start));//1000000条:4978

   JDBCUtils.closeResource(conn, ps);

  }

 

  

  第6章: 数据库事务

  6.1 数据库事务介绍

  
事务处理(事务操作):保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。

  
为确保数据库中数据的一致性,数据的操纵应当是离散的成组的逻辑单元:当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。

  
当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。

  
关闭数据库连接,数据就会自动的提交。如果多个操作,每个操作使用的是自己单独的连接,则无法保证事务。即同一个事务的多个操作必须在同一个连接下。

  
若此时 Connection 没有被关闭,还可能被重复使用,则需要恢复其自动提交状态 setAutoCommit(true)。尤其是在使用数据库连接池技术时,执行close()方法前,建议恢复自动提交状态。

  
// 3.进行数据库操作

   String sql1 = "update user_table set balance = balance - 100 where user = ?";

   update(conn, sql1, "AA");

   // 模拟网络异常

   //System.out.println(10 / 0);

   String sql2 = "update user_table set balance = balance + 100 where user = ?";

   update(conn, sql2, "BB");

   // 4.若没有异常,则提交事务

   conn.commit();

   } catch (Exception e) {

   e.printStackTrace();

   // 5.若有异常,则回滚事务

   try {

   conn.rollback();

   } catch (SQLException e1) {

   e1.printStackTrace();

   } finally {

   try {

   //6.恢复每次DML操作的自动提交功能

   conn.setAutoCommit(true);

   } catch (SQLException e) {

   e.printStackTrace();

   //7.关闭连接

   JDBCUtils.closeResource(conn, null, null);

  }

 

 

  其中,对数据库操作的方法为:

  

//使用事务以后的通用的增删改操作(version 2.0)

 

  public void update(Connection conn ,String sql, Object... args) {

   PreparedStatement ps = null;

   try {

   // 1.获取PreparedStatement的实例 (或:预编译sql语句)

   ps = conn.prepareStatement(sql);

   // 2.填充占位符

   for (int i = 0; i args.length; i++) {

   ps.setObject(i + 1, args[i]);

   // 3.执行sql语句

   ps.execute();

   } catch (Exception e) {

   e.printStackTrace();

   } finally {

   // 4.关闭资源

   JDBCUtils.closeResource(null, ps);

  }

 

  

  6.3 事务的ACID属性

  
原子性(Atomicity) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

  
一致性(Consistency) 事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

  
隔离性(Isolation) 事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

  
持久性(Durability) 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。

  
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:

  
脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的。

  
不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段。之后, T1再次读取同一个字段, 值就不同了。

  
幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行。之后, 如果 T1 再次读取同一个表, 就会多出几行。

  
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。

  
一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。

  
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE。 Oracle 默认的事务隔离级别为: READ COMMITED 。

  
每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个全局变量 @@tx_isolation, 表示当前的事务隔离级别。

  
设置当前 mySQL 连接的隔离级别:

  

set transaction isolation level read committed;

 

  
设置数据库系统的全局的隔离级别:

  

set global transaction isolation level read committed;

 

  
授予权限

  

#授予通过网络方式登录的tom用户,对所有库所有表的全部权限,密码设为abc123.

 

  grant all privileges on *.* to tom@% identified by abc123;

   #给tom用户使用本地命令行方式,授予atguigudb这个库下的所有表的插删改查的权限。

  grant select,insert,delete,update on atguigudb.* to tom@localhost identified by abc123;

 

  

  
DAO:Data Access Object访问数据信息的类和接口,包括了对数据的CRUD(Create、Retrival、Update、Delete),而不包含任何业务相关的信息。有时也称作:BaseDAO

  
import org.apache.commons.dbutils.QueryRunner;

  import org.apache.commons.dbutils.handlers.BeanHandler;

  import org.apache.commons.dbutils.handlers.BeanListHandler;

  import org.apache.commons.dbutils.handlers.ScalarHandler;

  
// getGenericSuperclass()用来获取当前类的父类的类型

   // ParameterizedType表示的是带泛型的类型

   ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();

   // 获取具体的泛型类型 getActualTypeArguments获取具体的泛型的类型

   // 这个方法会返回一个Type的数组

   Type[] types = parameterizedType.getActualTypeArguments();

   // 获取具体的泛型的类型·

   this.type = (Class T ) types[0];

   * 通用的增删改操作

   * @param sql

   * @param params

   * @return

   public int update(Connection conn,String sql, Object... params) {

   int count = 0;

   try {

   count = queryRunner.update(conn, sql, params);

   } catch (SQLException e) {

   e.printStackTrace();

   return count;

   * 获取一个对象

   * @param sql

   * @param params

   * @return

   public T getBean(Connection conn,String sql, Object... params) {

   T t = null;

   try {

   t = queryRunner.query(conn, sql, new BeanHandler T (type), params);

   } catch (SQLException e) {

   e.printStackTrace();

   return t;

   * 获取所有对象

   * @param sql

   * @param params

   * @return

   public List T getBeanList(Connection conn,String sql, Object... params) {

   List T list = null;

   try {

   list = queryRunner.query(conn, sql, new BeanListHandler T (type), params);

   } catch (SQLException e) {

   e.printStackTrace();

   return list;

   * 获取一个但一值得方。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: