数据库事物与blob的应用

来源:互联网 发布:餐饮软件破解版 编辑:程序博客网 时间:2024/06/05 09:58

 在数据库中,所谓事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。为确保数据库中数据的一致性,数据的操纵应当是离散的成组的逻辑单元:当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。
    事务的操作:先定义开始一个事务,然后对数据作修改操作,这时如果提交(COMMIT),这些修改就永久地保存下来,如果回退(ROLLBACK),数据库管理系统将放弃您所作的所有修改而回到开始事务时的状态。
   事务的ACID属性:
1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发

生。 
2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
3. 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响

  COMMIT和ROLLBACK语句的优点:

使用COMMIT 和 ROLLBACK语句,我们可以: 确保数据完整性。数据改变被提交之前预览。将逻辑上相关的操作分组。

   提交或回滚前的数据状态:
改变前的数据状态是可以恢复的,执行 DML 操作的用户可以通过 SELECT 语句查询提交或回滚之前的修正
其他用户不能看到当前用户所做的改变,直到当前用户结束事务。DML语句所涉及到的行被锁定, 其他用户不能操作。

   提交后的数据状态:

数据的改变已经被保存到数据库中。改变前的数据已经丢失。所有用户可以看到结果。锁被释放, 其他用户可以操作涉及到的数据。

   JDBC 事物处理:

   事务:指构成单个逻辑工作单元的操作集合
   事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚为了让多个 SQL 语句作为一个事务执行:调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务在出现异常时,调用 rollback(); 方法回滚事务

 

下面来看在mysql和oracle上加入数据的例子,这个里面牵涉到关于事物处理的语句.

这个是在oracle下插入图片:

package cn.itcast.jdbc;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import oracle.sql.BLOB;

public class TestOracleBlob {
 
 public static Connection getConnection(){
  Connection conn = null;
  
  String user = "system";
  String password = "itcast";
  String driver = "oracle.jdbc.driver.OracleDriver";
  String url = "jdbc:oracle:thin:@192.168.1.10:1521:orcl";
  
  try {
   Class.forName(driver);
   conn = DriverManager.getConnection(url, user, password);
  } catch (Exception e) {
   e.printStackTrace();
  }
  
  return conn;
 }
  public static void releaseDBSource(ResultSet rs, Statement st, Connection conn){
  try {
   if(rs != null)
    rs.close();
   if(st != null)
    st.close();
   if(conn != null)
    conn.close();
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }
  public static void insertBlob_1(){
  Connection conn = null;
  PreparedStatement ps = null;
  
  try {
   conn = getConnection();

   String sql = "INSERT INTO userinfo (name, picture) VALUES(?, ?)";
   ps = conn.prepareStatement(sql);
   ps.setString(1, "Bob12345");
   FileInputStream fis = new FileInputStream("ronaerdo.jpg");
   ps.setBinaryStream(2, fis, fis.available());
   ps.executeUpdate();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   //7. 关闭数据库资源
   releaseDBSource(null, ps, conn);
  }
 }
 public static void insertBlob(){
  Connection conn = null;
  Statement st = null;
  ResultSet rs = null;
  PreparedStatement ps = null;
  try {
   conn = getConnection();
   
   //0. 设置 Connection 为非自动提交, 因为需要进行两次操作
   conn.setAutoCommit(false);
   //需求: 向 orcl 数据库 userinfo 表中插入一条记录:
   //1. 插入一个空的 blob, 目标: 获取 pictuer 字段的指针
   String sql = "INSERT INTO userinfo (name, picture) VALUES('Jerry', empty_blob())";
    st = conn.createStatement();
    st.executeUpdate(sql);
  //向 userinfo 表的 'Tom' 记录中插入图片
  //2. 获取 picture 字段的指针
   sql = "SELECT picture FROM userinfo WHERE name = 'Jerry' for update";
   rs = st.executeQuery(sql);
   rs.next();
   BLOB picture = (BLOB) rs.getBlob(1);
    //3. 获取图片的输入流
   FileInputStream fis = new FileInputStream("car.jpg");
   //4. 获取 picture 字段的指针指向的数据区的输出流: 需要调用 oracle.sql.BLOB 的 getBinaryOutputStream(); 方法
   OutputStream os = null;
   os = picture.getBinaryOutputStream();
  //5. io 操作
   byte [] temp = new byte[1024 * 5];
   int length = 0;
   while((length = fis.read(temp)) != -1){
    os.write(temp, 0, length);
   }
   fis.close();
   os.close();
   //6. 提交数据
   conn.commit();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   try {
    //6. 回滚
    conn.rollback();
   } catch (SQLException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
   }
  }finally{
   //7. 关闭数据库资源
   
  }
 }
  public static void queryBlob(){
  //1. 建立数据库连接
  Connection conn = null;
  Statement st = null;
  ResultSet rs = null;
  try {
   conn = getConnection();
   //2. 准备 sql 文
   String sql = "SELECT picture FROM userinfo WHERE name = 'Jerry'";
   //3. 获取 Statement 对象
   st = conn.createStatement();
   //4. 查询操作
   rs = st.executeQuery(sql);
   //5. 处理结果集
   Blob picture = null;
    if(rs.next()){
    picture = rs.getBlob(1);
   }
   //6. 获取 picture 字段的输入流
   InputStream is = picture.getBinaryStream();
    //7. 建立输出流
   FileOutputStream pic = new FileOutputStream("myPic.jpg");
    //8. io 操作
   byte [] bytes = new byte[1024 * 5];
   int length = 0;
   while((length = is.read(bytes)) != -1){
    pic.write(bytes, 0, length);
   }
   is.close();
   pic.close();
   } catch (Exception e) {
   e.printStackTrace();
  }finally{
   //9. 关闭数据库资源
   releaseDBSource(rs, st, conn);
  }
 }
 
 public static void updateBlob(){
  Connection conn = null;
  Statement st = null;
  ResultSet rs = null;
  try {
   conn = getConnection();
   st = conn.createStatement();

   //1. 获取 picture 字段的指针
   String sql = "SELECT picture FROM userinfo WHERE name = 'Jerry' for update";
   rs = st.executeQuery(sql);
   rs.next();
   BLOB picture = (BLOB) rs.getBlob(1);
   //3. 获取图片的输入流
   FileInputStream fis = new FileInputStream("threadlocal.jpg");
   //4. 获取 picture 字段的指针指向的数据区的输出流: 需要调用 oracle.sql.BLOB 的 getBinaryOutputStream(); 方法
   OutputStream os = null;
   os = picture.getBinaryOutputStream();
   //5. io 操作
   byte [] temp = new byte[1024 * 5];
   int length = 0;
   while((length = fis.read(temp)) != -1){
    os.write(temp, 0, length);
   }
   fis.close();
   os.close();
   //6. 提交数据
   conn.commit();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   try {
    //6. 回滚
    conn.rollback();
   } catch (SQLException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
   }
  }finally{
   //7. 关闭数据库资源
   releaseDBSource(rs, st, conn);
  }
 }

 //删除二进制数据, 即: 让该字段的数据内容为空
 public static void deleteBlob(){
  Connection conn = null;
  Statement st = null;
  try {
   conn = getConnection();
   st = conn.createStatement();
   String sql = "UPDATE userinfo SET picture = empty_blob() WHERE name = 'Jerry'";
   st.execute(sql);
  } catch (SQLException e) {
   e.printStackTrace();
  }finally{
   releaseDBSource(null, st, conn);
  }
 }
 public static void main(String[] args) {
  //queryBlob();
  //updateBlob();
  //queryBlob();
  //deleteBlob();
  insertBlob_1();
 }
}

mysql的插入数据的方法 

package cn.itcast.jdbc;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestMysqlBlob {

 public static void main(String[] args) {
  //insertBlob(); 
  //updateBlob();
  deleteBlob();
 }
 public static Connection getConnection(){
  Connection conn = null;
  String user = "root";
  String password = "1230";
  String driver = "com.mysql.jdbc.Driver";
  String url = "jdbc:mysql://localhost:3309/itcast";
  try {
   Class.forName(driver);
   conn = DriverManager.getConnection(url, user, password);
  } catch (Exception e) {
   e.printStackTrace();
  }
  return conn;
 }
 public static void releaseDBSource(ResultSet rs, Statement st, Connection conn){
  try {
   if(rs != null)
    rs.close();
   if(st != null)
    st.close();
   if(conn != null)
    conn.close();
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }
 public static void deleteBlob(){
  Connection conn = null;
  PreparedStatement ps = null;
  String sql = "UPDATE userinfo SET picture = ? WHERE name = ?";
  try {
   conn = getConnection();
   ps = conn.prepareStatement(sql);
    //FileInputStream fis = new FileInputStream("myPic.jpg");
     ps.setString(2, "Tom");
    //不能使用 ps.setBlob(), 因为无法自己创建 Blob 对象
   ps.setBinaryStream(1, null, 0);
    ps.executeUpdate();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   releaseDBSource(null, ps, conn);
  }
 }
  public static void updateBlob(){
  Connection conn = null;
  PreparedStatement ps = null;
  String sql = "UPDATE userinfo SET picture = ? WHERE name = ?";
  try {
   conn = getConnection();
   ps = conn.prepareStatement(sql);
   FileInputStream fis = new FileInputStream("myPic.jpg");
   ps.setString(2, "Tom");
   //不能使用 ps.setBlob(), 因为无法自己创建 Blob 对象
   ps.setBinaryStream(1, fis, fis.available());
    ps.executeUpdate();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   releaseDBSource(null, ps, conn);
  }
 }
 public static void insertBlob(){
  Connection conn = null;
  PreparedStatement ps = null;
  String sql = "INSERT INTO userinfo(name, picture) VALUES(?, ?)";
  try {
   conn = getConnection();
   ps = conn.prepareStatement(sql);
   FileInputStream fis = new FileInputStream("1321554.jpg");
   ps.setString(1, "Tom");
   //不能使用 ps.setBlob(), 因为无法自己创建 Blob 对象
   ps.setBinaryStream(2, fis, fis.available());
   ps.executeUpdate();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }finally{
   releaseDBSource(null, ps, conn);
  }
 }

}

    MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。实际使用中根据需要存入的数据大小定义不同的BLOB类型。需要注意的是:如果存储的文件过大,数据库的性能会下降。
   使用JDBC来写入Blob型数据到Oracle中 :
1.Oracle的Blob字段比long字段的性能要好,可以用来保存如图片之类的二进制数据。
2.Oracle的BLOB字段由两部分组成:数据(值)和指向数据的指针(定位器)。尽管值与表自身一起存储,但是一个BLOB列并不包含值,仅有它的定位指针。为了使用大对象,程序必须声明定位器类型的本地变量。
3.当Oracle内部LOB被创建时,定位器被存放在列中,值被存放在LOB段中,LOB段是在数据库内部表的一部分。
4.因为Blob自身有一个cursor,当写入Blob字段必须使用指针(定位器)对Blob进行操作,因而在写入Blob之前,必须获得指针(定位器)才能进行写入
5.如何获得Blob的指针(定位器):需要先插入一个empty的blob,这将创建一个blob的指针,然后再把这个empty的blob的c指针查询出来,这样通过两步操作,就获得了blob的指针,可以真正的写入blob数据了。

如果将一些重要的数据导入数据库中是很安全的,除非你的数据库的密码被别人事先已经知道,否则任何人都盗取不到任何信息的!只有用户名和密码的人才能够看到数据里面的内容的!

 

原创粉丝点击