JavaEE

JavaWeb基础恢复之操作数据库

2018-04-26  本文已影响8人  平安喜乐698
目录

 JDBC
    Java Data Base Connectivity(java数据库连接)
    

 应用
 JDBC  (位于第二层)
 各种数据库驱动
 数据库
1. 使用
下载mysql-connector-java-8.0.11.jar,并放入WEB-INF | lib下

下载mysql-connector-java-8.0.11.jar , 选Platform Indepentdent

简单使用

  1. 创建数据库、表、插入数据
终端输入sql

create database Test character set utf8 collate utf8_general_ci;

use Test;

create table users(
    id int primary key,
    name varchar(40),
    password varchar(40),
    email varchar(60),
    birthday date
);

insert into users(id,name,password,email,birthday) values(1,'zhansan','123456','xx@sina.com','2220-12-04');
insert into users(id,name,password,email,birthday) values(2,'lisi','123456','xx@sina.com','2222-12-04');
insert into users(id,name,password,email,birthday) values(3,'wangwu','123456','xx@sina.com','2222-12-04');

Navicat Premium可视化工具连接本地数据库

localhost
3306
root
数据库密码

2.数据库操作类

package com.sst.cx;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class TestJSDBCModel {
       public static void main(String[] args) throws Exception {

            
            // 1.加载驱动
            /*不推荐使用这种方式来加载驱动
              DriverManager.registerDriver(new com.mysql.jdbc.Driver());
                1、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
                2、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
             * */
            // 推荐使用
            Class.forName("com.mysql.jdbc.Driver"); 
            
            /* 2.1 设置 要连接的数据库URL
             * 协议:子协议:主机:端口号/数据库名
             * 
                Oracle写法:jdbc:oracle:thin:@localhost:1521:sid
                SqlServer写法:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid
                MySql写法:jdbc:mysql://localhost:3306/sid
             */
            String url = "jdbc:mysql://localhost:3306/数据库名";
            // 2.2 设置 连接的数据库时使用的用户名
            String username = "root";
            // 2.3 设置 连接的数据库时使用的密码
            String password = "密码";
            // 2.4 获取 与数据库的链接
            Connection conn = DriverManager.getConnection(url, username, password);
            /*
             Connection类
                createStatement():创建向数据库发送sql的statement对象。
                prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象。
                prepareCall(sql):创建执行存储过程的callableStatement对象。
                setAutoCommit(boolean autoCommit):设置事务是否自动提交。
                commit() :在链接上提交事务。
                rollback() :在此链接上回滚事务。
             * */
            // 3. 获取 用于向数据库发送sql语句的statement
            Statement st = conn.createStatement();
            /*
             Statement类
                executeQuery(String sql) :用于向数据发送查询语句。
                executeUpdate(String sql):用于向数据库发送insert、update或delete语句
                execute(String sql):用于向数据库发送任意sql语句
                addBatch(String sql) :把多条sql语句放到一个批处理中。
                executeBatch():向数据库发送一批sql语句执行。
             * */
            
            // -----------增-----------
            String insertSql = "insert into user(….) values(…..) "; 
            int num = st.executeUpdate(insertSql);
            if(num>0){
                System.out.println("插入成功!!!");
            }
            
            // -----------删-----------
            String sql = "delete from user where id=1"; 
            int deleNum = st.executeUpdate(sql);
            if(deleNum>0){
                System.out.println("删除成功!!!");
            }
            
            // -----------改-----------
            String updateSql = "update user set name='' where name=''"; 
            int updateNum = st.executeUpdate(updateSql);
            if(updateNum>0){
                System.out.println("修改成功!!!");
            }
            
            // -----------查-----------
            String querySql = "select id,name,password,email,birthday from users";
            // 4.向数据库发sql,并获取代表结果集的resultset
            ResultSet rs = st.executeQuery(querySql);
            /*
             ResultSet类
                getObject(int index)
                getObject(string columnName)

                // 指定数据类型
                getString(int index)
                getString(String columnName)
                。。。


                next():移动到下一行
                Previous():移动到前一行
                absolute(int row):移动到指定行
                beforeFirst():移动resultSet的最前面。
                afterLast() :移动到resultSet的最后面。

             * */
            // 5.取出结果集的数据
            while(rs.next()){
                // 获取 字段值
                System.out.println("id=" + rs.getObject("id"));
                System.out.println("name=" + rs.getObject("name"));
                System.out.println("password=" + rs.getObject("password"));
                System.out.println("email=" + rs.getObject("email"));
                System.out.println("birthday=" + rs.getObject("birthday"));
            }
            
            // 6.关闭链接,释放资源
            rs.close();
            st.close();
            conn.close();
        }
}
遇到的错误:java.lang.UnsupportedClassVersionError
解决:
    换jdk版本为高版本即可
    MyEclipse|设置|Java|JRE换jdk版本


查看jdk版本
    /usr/libexec/java_home -V

规范使用

  1. 新建db.properties
在src下新建File

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/Test
username=root
password=密码
  1. 新建数据库处理类
package com.sst.cx;

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {

    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;
    
    static{
        try{
            // 读取db.properties文件中的数据库连接信息
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc2.properties");

            Properties prop = new Properties();
            prop.load(in);
            
            //获取数据库连接驱动
            driver = prop.getProperty("driver");
            //获取数据库连接URL地址
            url = prop.getProperty("url");
            //获取数据库连接用户名
            username = prop.getProperty("username");
            //获取数据库连接密码
            password = prop.getProperty("password");
            
            //加载数据库驱动
            Class.forName(driver);
            
        }catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    
    /**
    * @Method: getConnection
    * @Description: 获取数据库连接对象
    *
    * @return Connection数据库连接对象
    * @throws SQLException
    */ 
    public static Connection getConnection() throws SQLException{
        return DriverManager.getConnection(url, username,password);
    }
    
    /**
    * @Method: release
    * @Description: 释放资源,
    *     要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
    *
    * @param conn
    * @param st
    * @param rs
    */ 
    public static void release(Connection conn,Statement st,ResultSet rs){
        if(rs!=null){
            try{
                //关闭存储查询结果的ResultSet对象
                rs.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if(st!=null){
            try{
                //关闭负责执行SQL命令的Statement对象
                st.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        if(conn!=null){
            try{
                //关闭Connection数据库连接对象
                conn.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3.处理类

package com.sst.cx;

import java.sql.*;

public class TestJdbcM {
  
    public static void main(String[] args){
        (new TestJdbcM()).insert();
    }
    
    /*
     create database Test;

    use Test;

    create table users(
        id int primary key,
        name varchar(40),
        password varchar(40),
        email varchar(60),
        birthday date
    );

     * */
    // 增
    public void insert(){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try{
            //获取一个数据库连接
            conn = JdbcUtils.getConnection();
            //通过conn对象获取负责执行SQL命令的Statement对象
            st = conn.createStatement();
            //要执行的SQL命令
            String sql = "insert into users(id,name,password,email,birthday) values(6,'ss','123','xx@qq.com','2222-02-02')";
            //执行插入操作,executeUpdate方法返回成功的条数
            int num = st.executeUpdate(sql);
            if(num>0){
                System.out.println("插入成功!!");
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            //SQL执行完成之后释放相关资源
            JdbcUtils.release(conn, st, rs);
        }
    }
    
    // 删
    public void delete(){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try{
            conn = JdbcUtils.getConnection();
            String sql = "delete from users where id=3";
            st = conn.createStatement();
            int num = st.executeUpdate(sql);
            if(num>0){
                System.out.println("删除成功!!");
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, st, rs);
        }
    }
    
    // 改
    public void update(){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try{
            conn = JdbcUtils.getConnection();
            String sql = "update users set name='hello',email='xxxx@sina.com' where id=3";
            st = conn.createStatement();
            int num = st.executeUpdate(sql);
            if(num>0){
                System.out.println("更新成功!!");
            }
        }catch (Exception e) {
            e.printStackTrace();
            
        }finally{
            JdbcUtils.release(conn, st, rs);
        }
    }
    
    // 查
    public void find(){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try{
            conn = JdbcUtils.getConnection();
            String sql = "select * from users where id=3";
            st = conn.createStatement();
            rs = st.executeQuery(sql);
            if(rs.next()){
                System.out.println(rs.getString("name"));
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, st, rs);
        }
    }
}

4.处理类2(占位符)

public class JdbcCRUDByPreparedStatement {
     
// 增     
public void insert(){
    Connection conn = null;
    PreparedStatement st = null;
    ResultSet rs = null;
    try{
        // 获取一个数据库连接
        conn = JdbcUtils.getConnection();
        // 要执行的SQL命令,SQL中的参数使用?作为占位符
        String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";
        // 通过conn对象获取负责执行SQL命令的prepareStatement对象
        st = conn.prepareStatement(sql);
        // 为SQL语句中的参数赋值,注意,索引是从1开始的
        /**
        * SQL语句中各个字段的类型如下:
        *  +----------+-------------+
        | Field    | Type        |
        +----------+-------------+
        | id       | int(11)     |
        | name     | varchar(40) |
        | password | varchar(40) |
        | email    | varchar(60) |
        | birthday | date        |
        +----------+-------------+
        */
        st.setInt(1, 1);    //    id是int类型的
        st.setString(2, "hello");//name是varchar(字符串类型)
        st.setString(3, "123");//password是varchar(字符串类型)
        st.setString(4, "xx@sina.com");//email是varchar(字符串类型)
        st.setDate(5, new java.sql.Date(new Date().getTime()));//birthday是date类型
        //执行插入操作,executeUpdate方法返回成功的条数
        int num = st.executeUpdate();
        if(num>0){
           System.out.println("插入成功!!");
        }

        }catch (Exception e) {
             e.printStackTrace();
        }finally{
             //SQL执行完成之后释放相关资源
             JdbcUtils.release(conn, st, rs);
        }
}


// 删
public void delete(){
   Connection conn = null;
   PreparedStatement st = null;
   ResultSet rs = null;
   try{
       conn = JdbcUtils.getConnection();
       String sql = "delete from users where id=?";
       st = conn.prepareStatement(sql);
       st.setInt(1, 1);
       int num = st.executeUpdate();
       if(num>0){
           System.out.println("删除成功!!");
       }
   }catch (Exception e) {
       e.printStackTrace();
   }finally{
       JdbcUtils.release(conn, st, rs);
   }
}


// 改
public void update(){
   Connection conn = null;
   PreparedStatement st = null;
   ResultSet rs = null;
   try{
       conn = JdbcUtils.getConnection();
       String sql = "update users set name=?,email=? where id=?";
       st = conn.prepareStatement(sql);
       st.setString(1, "gacl");
       st.setString(2, "gacl@sina.com");
       st.setInt(3, 2);
       int num = st.executeUpdate();
       if(num>0){
           System.out.println("更新成功!!");
       }
   }catch (Exception e) {
       e.printStackTrace();
       
   }finally{
       JdbcUtils.release(conn, st, rs);
   }
}


// 查
public void find(){
   Connection conn = null;
   PreparedStatement st = null;
   ResultSet rs = null;
   try{
       conn = JdbcUtils.getConnection();
       String sql = "select * from users where id=?";
       st = conn.prepareStatement(sql);
       st.setInt(1, 1);
       rs = st.executeQuery();
       if(rs.next()){
           System.out.println(rs.getString("name"));
       }
   }catch (Exception e) {
       
   }finally{
       JdbcUtils.release(conn, st, rs);
   }
}
}
获取数据库自动生成的主键
     id int primary key auto_increment
 
     String sql = "insert into test1(name) values(?)";
     st = conn.prepareStatement(sql);
     st.setString(1, "aaa");
     st.executeUpdate();
     // 获取数据库自动生成的主键
     rs = st.getGeneratedKeys();
     if(rs.next()){
       System.out.println(rs.getInt(1));
     }
2. 事务

概念

原子性(Atomicity)  �
    原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败

一致性(Consistency)
    �事务必须使数据库从一个一致性状态变换到另外一个一致性状态。以转账为例子,A向B转账,假设转账之前这两个用户的钱加起来总共是2000,那么A向B转账之后,不管这两个账户怎么转,A用户的钱和B用户的钱加起来的总额还是2000,这个就是事务的一致性。

隔离性(Isolation)复杂,详细介绍在下�
    事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

持久性(Durability)
     持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
事务的隔离级别 
    多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。
 
事务不考虑隔离性可能会引发的问题:
   1、脏读
      脏读指一个事务读取了另外一个事务未提交的数据。
 
      这是非常危险的,假设A向B转帐100元,对应sql语句如下所示
       1.update account set money=money+100 where name='B';
       2.update account set money=money-100  where name='A';
       当第1条sql执行完,第2条还没执行(A未提交时),如果此时B查询自己的帐户,就会发现自己多了100元钱。如果A等B走后再回滚,B就会损失100元。
   2、不可重复读
       不可重复读指在一个事务内读取表中的某一行数据,多次读取结果不同。
    3、虚读(幻读)
       虚读(幻读)是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。


MySQL数据库共定义了四种隔离级别: 
   1.当把事务的隔离级别设置为read uncommitted时,会引发脏读、不可重复读和虚读
   A窗口
     set transaction isolation level  read uncommitted;--设置A用户的数据库隔离级别为Read uncommitted(读未提交)
     start transaction;--开启事务
     select * from account;--查询A账户中现有的钱,转到B窗口进行操作
     select * from account--发现a多了100元,这时候A读到了B未提交的数据(脏读)
   B窗口
     start transaction;--开启事务
     update account set money=money+100 where name='A';--不要提交,转到A窗口查询
 
 
   2.当把事务的隔离级别设置为read committed时,会引发不可重复读和虚读,但避免了脏读
   A窗口
     set transaction isolation level  read committed;
     start transaction;
     select * from account;--发现a帐户是1000元,转到b窗口
     select * from account;--发现a帐户多了100,这时候,a读到了别的事务提交的数据,两次读取a帐户读到的是不同的结果(不可重复读)
   B窗口
     start transaction;
     update account set money=money+100 where name='aaa';
     commit;--转到a窗口
 
 
   3.当把事务的隔离级别设置为repeatable read(mysql默认级别)时,会引发虚读,但避免了脏读、不可重复读
   A窗口
     set transaction isolation level repeatable read;
     start transaction;
     select * from account;--发现表有4个记录,转到b窗口
     select * from account;--可能发现表有5条记录,这时候发生了a读取到另外一个事务插入的数据(虚读)
   B窗口
     start transaction;
     insert into account(name,money) values('ggg',1000);
     commit;--转到a窗口
 
 
   4.当把事务的隔离级别设置为Serializable时,会避免所有问题
   A窗口
     set transaction isolation level Serializable;
     start transaction;
     select * from account;--转到b窗口
   B窗口
     start transaction;
     insert into account(name,money) values('ggg',1000);--发现不能插入,只能等待a结束事务才能插入


 终端查询当前事务隔离级别:select @@tx_isolation
 mysql数据库默认的事务隔离级别是:Repeatable read(可重复读)
 set transaction isolation level 隔离级别名

使用

终端使用

// 开启事务
start transaction;
// 执行语句列表。。。
// 提交
commit;
 
// 回滚(异常中)
rollback;
代码使用
    conn.setAutoCommit(false); // 通知数据库开启事务
 
public void testTransaction1(){
     Connection conn = null;
     PreparedStatement st = null;
     ResultSet rs = null;
 
     try{
       conn = JdbcUtils.getConnection();
       conn.setAutoCommit(false);//通知数据库开启事务(start transaction)
       String sql1 = "update account set money=money-100 where name='A'";
       st = conn.prepareStatement(sql1);
       st.executeUpdate();
       String sql2 = "update account set money=money+100 where name='B'";
       st = conn.prepareStatement(sql2);
       st.executeUpdate();
       conn.commit();//上面的两条SQL执行Update语句成功之后就通知数据库提交事务(commit)
       System.out.println("成功!!!");  //log4j
     }catch (Exception e) {
       e.printStackTrace();
     }finally{
       JdbcUtils.release(conn, st, rs);
     }
 }
设置事物回滚点
 
 
 // 设置事务回滚点
 sp = conn.setSavepoint();
 
 异常中+
 conn.rollback(sp);//回滚到设置的事务回滚点
 // 回滚了要记得通知数据库提交事务
 conn.commit();
3. 批处理
JDBC实现批处理有两种方式:statement和preparedstatement
Statement完成批处理
 
    st = conn.createStatement();
    // 添加要批量执行的SQL
    st.addBatch(sql1);
    st.addBatch(sql2);
    // 执行批处理SQL语句
    st.executeBatch();
    // 清除批处理命令
    st.clearBatch();
 
    优点:可以向数据库发送多条不同的SQL语句。
    缺点:SQL语句没有预编译。
   当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句
 PreparedStatement完成批处理

    String sql = "insert into testbatch(id,name) values(?,?)";
    st = conn.prepareStatement(sql);
    for(int i=1;i<1000008;i++){  //i=1000  2000
        st.setInt(1, i);
        st.setString(2, "aa" + i);
        st.addBatch();
        if(i%1000==0){
            st.executeBatch();
            st.clearBatch();
        }
    }
    st.executeBatch();
 
    优点:发送的是预编译后的SQL语句,执行效率高。
    缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。
4. 大数据
大数据LOB(Large Objects)分为:
      clob用于存储大文本
      blob用于存储二进制数据,例如图像、声音、二进制文等。

MySQL

MySQL
      blob(没有clob)存储二进制,分为:
       TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB
      Text存储大文本,分为:
       TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT
大文本

sql 
    helloContent text类型
 
添加
 // 这种方式获取的路径,其中的空格会被使用“%20”代替
 String path = JdbcOperaClob.class.getClassLoader().getResource("data.txt").getPath();
 // 将“%20”替换回空格
 path = path.replaceAll("%20", " ");
 File file = new File(path);
 reader = new FileReader(file);
 st.setCharacterStream(1, reader,(int) file.length());
 int num = st.executeUpdate();
 if(num>0){
     System.out.println("插入成功!!");
 }
 //关闭流
 reader.close();
 
 
 
读取 
 String sql = "select resume from testclob where id=2";
 st = conn.prepareStatement(sql);
 rs = st.executeQuery();
 
 String contentStr ="";
 String content = "";
 if(rs.next()){
     //使用resultSet.getString("字段名")获取大文本数据的内容
     content = rs.getString("resume");
     //使用resultSet.getCharacterStream("字段名")获取大文本数据的内容
     Reader reader = rs.getCharacterStream("resume");
     char buffer[] = new char[1024];
     int len = 0;
     FileWriter out = new FileWriter("D:\\1.txt");
     while((len=reader.read(buffer))>0){
       contentStr += new String(buffer);
       out.write(buffer, 0, len);
     }
     out.close();
     reader.close();
 }
二进制

sql
 helloImage longblob类型
 
  
添加
 conn = JdbcUtils.getConnection();
 String sql = "insert into testblob(image) values(?)";
 st = conn.prepareStatement(sql);
 //这种方式获取的路径,其中的空格会被使用“%20”代替
 String path = JdbcOperaBlob.class.getClassLoader().getResource("01.jpg").getPath();
 //将“%20”替换会空格
 path = path.replaceAll("%20", " ");
 File file = new File(path);
 FileInputStream fis = new FileInputStream(file);//生成的流
 st.setBinaryStream(1, fis,(int) file.length());
 int num = st.executeUpdate();
 if(num>0){
     System.out.println("插入成功!!");
 }
 fis.close();
 
 
读取
 String sql = "select image from testblob where id=?";
 st = conn.prepareStatement(sql);
 st.setInt(1, 1);
 rs = st.executeQuery();
 if (rs.next()) {
     //InputStream in = rs.getBlob("image").getBinaryStream();//这种方法也可以
     InputStream in = rs.getBinaryStream("image");
     int len = 0;
     byte buffer[] = new byte[1024];
 
     FileOutputStream out = new FileOutputStream("D:\\1.jpg");
     while ((len = in.read(buffer)) > 0) {
       out.write(buffer, 0, len);
     }
     in.close();
     out.close();
 }

Oracle

LOB(Large Object,大型对象)类型的字段现在用得越来越多了。
    因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种类型的字段,很灵活,适用于数据 量非常大的业务领域(如图象、档案等)。
 
LOB类型分为种:
        BLOB二进制大型对象(Binary Large Object)
        CLOB字符型大型对象(Character Large Object)
sql
    CREATE TABLE TEST_CLOB ( ID NUMBER(3), CLOBCOL CLOB)
    CREATE TABLE TEST_BLOB ( ID NUMBER(3), BLOBCOL BLOB)

db.properties
    oracleDb_Driver=oracle.jdbc.driver.OracleDriver
    oracleDb_Url=jdbc:oracle:thin:@localhost:1521:GACL
    oracleDb_UserName=GACL_XDP
    oracleDb_Password=P

数据库处理类
public class JdbcUtils {

    private static String oracleDb_Driver = null;
    private static String oracleDb_Url = null;
    private static String oracleDb_UserName = null;
    private static String oracleDb_Password = null;

    static{
        try{
        //读取db.properties文件中的数据库连接信息
        InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
        Properties prop = new Properties();
        prop.load(in);

        //获取数据库连接驱动
        oracleDb_Driver = prop.getProperty("oracleDb_Driver");
        //获取数据库连接URL地址
        oracleDb_Url = prop.getProperty("oracleDb_Url");
        //获取数据库连接用户名
        oracleDb_UserName = prop.getProperty("oracleDb_UserName");
        //获取数据库连接密码
        oracleDb_Password = prop.getProperty("oracleDb_Password");

        //加载数据库驱动
        Class.forName(oracleDb_Driver);

        }catch (Exception e) {
          throw new ExceptionInInitializerError(e);
        }
  }

   //获取Oracle数据库连接对象
   public static Connection getOracleConnection() throws SQLException{
       return DriverManager.getConnection(oracleDb_Url, oracleDb_UserName,oracleDb_Password);
   }

   // 要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
   public static void release(Connection conn,Statement st,ResultSet rs){
       if(rs!=null){
           try{
               //关闭存储查询结果的ResultSet对象
               rs.close();
           }catch (Exception e) {
               e.printStackTrace();
           }
           rs = null;
       }
       if(st!=null){
           try{
               //关闭负责执行SQL命令的Statement对象
               st.close();
           }catch (Exception e) {
               e.printStackTrace();
           }
       }
   
       if(conn!=null){
           try{
               //关闭Connection数据库连接对象
               conn.close();
           }catch (Exception e) {
               e.printStackTrace();
           }
       }
   }
}
CLOB数据 字符型
 
 public class JdbcOperaOracleClob {
 
// 往数据库中插入一个新的CLOB对象
public void clobInsert() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    conn = JdbcUtils.getOracleConnection();
    boolean defaultCommit = conn.getAutoCommit();
    // 开启事务,设定不自动提交
    conn.setAutoCommit(false);
    try {
        // 插入一个空的CLOB对象
        String sql = "INSERT INTO TEST_CLOB VALUES (?, EMPTY_CLOB())";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        stmt.executeUpdate();
        // 查询此CLOB对象并锁定
        sql = "SELECT CLOBCOL FROM TEST_CLOB WHERE ID=? FOR UPDATE";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            // 取出此CLOB对象
            oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob("CLOBCOL");
            // 向CLOB对象中写入数据
            BufferedWriter out = new BufferedWriter(clob.getCharacterOutputStream());
            //这种方式获取的路径,其中的空格会被使用“%20”代替
            String path = JdbcOperaClob.class.getClassLoader().getResource("data.txt").getPath();
            // 将“%20”替换回空格
            path = path.replaceAll("%20", " ");
            BufferedReader in = new BufferedReader(new FileReader(path));
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            in.close();
            out.close();
        }
        // 正式提交
        conn.commit();
        System.out.println("插入成功");
    } catch (Exception ex) {
        // 出错回滚
        conn.rollback();
        throw ex;
    }finally{
        // 恢复原提交状态
        conn.setAutoCommit(defaultCommit);
        JdbcUtils.release(conn,stmt,rs);
    }
    
}
 
// CLOB对象读取
public void clobRead() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    conn = JdbcUtils.getOracleConnection();
    boolean defaultCommit = conn.getAutoCommit();
    conn.setAutoCommit(false);
    try {
        // 查询CLOB对象
        String sql = "SELECT * FROM TEST_CLOB WHERE ID=?";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            // 获取CLOB对象
            oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob("CLOBCOL");
            // 以字符形式输出
            BufferedReader in = new BufferedReader(clob.getCharacterStream());
            BufferedWriter out = new BufferedWriter(new FileWriter("D:\\2.txt"));
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            out.close();
            in.close();
        }
    } catch (Exception ex) {
        conn.rollback();
        throw ex;
    }finally{
        // 恢复原提交状态
        conn.setAutoCommit(defaultCommit);
        JdbcUtils.release(conn,stmt,rs);
    }
}


// 修改CLOB对象(是在原CLOB对象基础上进行覆盖式的修改)
public void clobModify() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    conn = JdbcUtils.getOracleConnection();
    boolean defaultCommit = conn.getAutoCommit();
    // 开启事务
    conn.setAutoCommit(false);
    try {
        // 查询CLOB对象并锁定
        String sql = "SELECT CLOBCOL FROM TEST_CLOB WHERE ID=? FOR UPDATE";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            // 获取此CLOB对象
            oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob("CLOBCOL");
            // 进行覆盖式修改
            BufferedWriter out = new BufferedWriter(clob.getCharacterOutputStream());
            // 这种方式获取的路径,其中的空格会被使用“%20”代替
            String path = JdbcOperaClob.class.getClassLoader().getResource("data2.txt").getPath();
            // 将“%20”替换回空格
            path = path.replaceAll("%20", " ");
            BufferedReader in = new BufferedReader(new FileReader(path));
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            in.close();
            out.close();
        }
        //提交事务
        conn.commit();
    } catch (Exception ex) {
        // 出错回滚事务
        conn.rollback();
        throw ex;
    }finally{
        // 恢复原提交状态
        conn.setAutoCommit(defaultCommit);
        JdbcUtils.release(conn,stmt,rs);
    }
}


// 替换CLOB对象(将原CLOB对象清除,换成一个全新的CLOB对象)
public void clobReplace() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    conn = JdbcUtils.getOracleConnection();
    boolean defaultCommit = conn.getAutoCommit();
    // 开启事务
    conn.setAutoCommit(false);
    try {
        // 清空原CLOB对象
        String sql = "UPDATE TEST_CLOB SET CLOBCOL=EMPTY_CLOB() WHERE ID=?";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        stmt.executeUpdate();
        
        // 查询CLOB对象并锁定
        sql = "SELECT CLOBCOL FROM TEST_CLOB WHERE ID=? FOR UPDATE";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            // 获取此CLOB对象
            oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob("CLOBCOL");
            // 更新数据
            BufferedWriter out = new BufferedWriter(clob.getCharacterOutputStream());
            // 这种方式获取的路径,其中的空格会被使用“%20”代替
            String path = JdbcOperaClob.class.getClassLoader().getResource("db.properties").getPath();
            // 将“%20”替换回空格
            path = path.replaceAll("%20", " ");
            BufferedReader in = new BufferedReader(new FileReader(path));
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            in.close();
            out.close();
        }
        // 正式提交
        conn.commit();
    } catch (Exception ex) {
        // 出错回滚
        conn.rollback();
        throw ex;
    } finally {
        // 恢复原提交状态
        conn.setAutoCommit(defaultCommit);
        JdbcUtils.release(conn, stmt, rs);
    }
}
}
 处理BLOB二进制数据
 
    Oracle定义了一个BLOB字段用于保存二进制数据,但这个字段并不能存放真正的二进制数据,只能向这个字段存一个指针,然后把数据放到指针所指向的Oracle的LOB段中, LOB段是在数据库内部表的一部分。因而在操作Oracle的Blob之前,必须获得指针(定位器)才能进行Blob数据的读取和写入。
   如何获得表中的Blob指针呢? 可以先使用insert语句向表中插入一个空的blob(调用oracle的函数empty_blob()),这将创建一个blob的指针,然后再把这个empty的blob的指针查询出来,这样就可得到BLOB对象,从而读写blob数据了。
 
   1、插入空blob:insert into testblob(id,image) values(?,empty_blob())
   2、获得blob的cursor:
     select image from testblob where id=? for update �注意: 必 须加for update锁定该行,直至该行被修改完毕,保证不产生并发冲突。
     Blob b = rs.getBlob("image");
   3、利用 io和获取到的cursor往数据库读写数据
   注意:以上操作需开启事务。
 
 
 
 public class JdbcOperaOracleBlob {
 
// 向数据库中插入一个新的BLOB对象
public void blobInsert() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    boolean defaultCommit = true;
    try {
        conn = JdbcUtils.getOracleConnection();
        //得到数据库事务处理的默认提交方式
        defaultCommit = conn.getAutoCommit();
        //1、开启事务
        conn.setAutoCommit(false);
        //2、插入一个空的BLOB对象
        String sql = "INSERT INTO TEST_BLOB VALUES (?, EMPTY_BLOB())";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        stmt.executeUpdate();
        //3、查询此BLOB对象并锁定。注意: 必 须加for update锁定该行,直至该行被修改完毕,保证不产生并发冲突
        sql = "SELECT BLOBCOL FROM TEST_BLOB WHERE ID=? FOR UPDATE";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            //4、取出此BLOB对象 ,并强制转换成Oracle的BLOB对象
            oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob("BLOBCOL");
            //5、使用IO向BLOB对象中写入数据
            BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
            BufferedInputStream in = new BufferedInputStream(JdbcOperaOracleBlob.class.getClassLoader().getResourceAsStream("01.jpg"));
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            in.close();
            out.close();
        }
        //6、提交事务
        conn.commit();
    } catch (Exception ex) {
        //7、出错回滚事务
        conn.rollback();
        throw ex;
    } finally {
        //8、恢复数据库事务处理的默认提交方式
        conn.setAutoCommit(defaultCommit);
        //释放资源
        JdbcUtils.release(conn, stmt, rs);
    }
    
}


// 修改BLOB对象(是在原BLOB对象基础上进行覆盖式的修改)
public void blobModify() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    boolean defaultCommit = true;
    try {
        conn = JdbcUtils.getOracleConnection();
        //得到数据库事务处理的默认提交方式
        defaultCommit = conn.getAutoCommit();
        //1、开启事务
        conn.setAutoCommit(false);
        //2、查询此BLOB对象并锁定。注意: 必 须加for update锁定该行,直至该行被修改完毕,保证不产生并发冲突
        String sql = "SELECT BLOBCOL FROM TEST_BLOB WHERE ID=? FOR UPDATE";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            //3、取出此BLOB对象 ,并强制转换成Oracle的BLOB对象
            oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob("BLOBCOL");
            //4、使用IO向BLOB对象中写入数据
            BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
            BufferedInputStream in = new BufferedInputStream(JdbcOperaOracleBlob.class.getClassLoader().getResourceAsStream("02.jpg"));
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            in.close();
            out.close();
        }
        //5、提交事务
        conn.commit();
    } catch (Exception ex) {
        //6、出错回滚事务
        conn.rollback();
        throw ex;
    } finally {
        //8、恢复数据库事务处理的默认提交方式
        conn.setAutoCommit(defaultCommit);
        //释放资源
        JdbcUtils.release(conn, stmt, rs);
    }
}

// 替换BLOB对象(将原BLOB对象清除,换成一个全新的BLOB对象)
public void blobReplace() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    boolean defaultCommit = true;
    try {
        conn = JdbcUtils.getOracleConnection();
        //得到数据库事务处理的默认提交方式
        defaultCommit = conn.getAutoCommit();
        //1、开启事务
        conn.setAutoCommit(false);
        //2、清空原BLOB对象
        String sql = "UPDATE TEST_BLOB SET BLOBCOL=EMPTY_BLOB() WHERE ID=?";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        stmt.executeUpdate();
        //3、查询此BLOB对象并锁定。注意: 必 须加for update锁定该行,直至该行被修改完毕,保证不产生并发冲突
        sql = "SELECT BLOBCOL FROM TEST_BLOB WHERE ID=? FOR UPDATE";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            //4、取出此BLOB对象 ,并强制转换成Oracle的BLOB对象
            oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob("BLOBCOL");
            //5、使用IO向BLOB对象中写入数据
            BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
            BufferedInputStream in = new BufferedInputStream(JdbcOperaOracleBlob.class.getClassLoader().getResourceAsStream("01.jpg"));
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            in.close();
            out.close();
        }
        //6、提交事务
        conn.commit();
    } catch (Exception ex) {
        //7、出错回滚事务
        conn.rollback();
        throw ex;
    } finally {
        //8、恢复数据库事务处理的默认提交方式
        conn.setAutoCommit(defaultCommit);
        //释放资源
        JdbcUtils.release(conn, stmt, rs);
    }
}

// BLOB对象读取
public void blobRead() throws Exception {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    boolean defaultCommit = true;
    try {
        conn = JdbcUtils.getOracleConnection();
        //得到数据库事务处理的默认提交方式
        defaultCommit = conn.getAutoCommit();
        //1、开启事务
        conn.setAutoCommit(false);
        //2、查询BLOB对象
        String sql = "SELECT BLOBCOL FROM TEST_BLOB WHERE ID=?";
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, 1);
        rs = stmt.executeQuery();
        if (rs.next()) {
            //3、取出此BLOB对象 ,并强制转换成Oracle的BLOB对象
            oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob("BLOBCOL");
            //4、以二进制流的形式输出
            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("D:/1.jpg"));
            BufferedInputStream in = new BufferedInputStream(blob.getBinaryStream());
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
            in.close();
            out.close();
        }
        //5、提交事务
        conn.commit();
    } catch (Exception ex) {
        //6、出错回滚事务
        conn.rollback();
        throw ex;
    } finally {
        //8、恢复数据库事务处理的默认提交方式
        conn.setAutoCommit(defaultCommit);
        //释放资源
        JdbcUtils.release(conn, stmt, rs);
    }
    
}}
 通过JDBC操纵Oracle数据库的LOB字段,不外乎插入、修改、替换、读取四种方式,掌握起来并不难。观察上述程序对LOB类型字段的存取,我们可以看出,较之其它类型字段,有下面几个显著不同的特点:
 
   1、必须取消自动提交。
 
   存取操作开始前,必须用setAutoCommit(false)取消自动提交。其它类型字段则无此特殊要求。这是因为存取LOB类型字段时,通常要进行多次操作可以完成。不这样的话,Oracle将抛出“读取违反顺序”的错误。
 
   2、插入方式不同。
 
   LOB数据不能象其它类型数据一样直接插入(INSERT)。插入前必须先插入一个空的LOB对象,CLOB类型 的空对象为EMPTY_CLOB(),BLOB类型的空对象为EMPTY_BLOB()。之后通过SELECT命令查询得到先前插入的记录并锁定,继而将 空对象修改为所要插入的LOB对象。
 
   3、修改方式不同。
 
   其它类型的字段修改时,用UPDATE … SET…命令即可。而LOB类型字段,则只能用SELECT … FOR UPDATE命令将记录查询出来并锁定,然后才能修改。且修改也有两种改法:一是在原数据基础上的修改(即覆盖式修改),执行SELECT … FOR UPDATE后再改数据;二是替换(先将原数据清掉,再修改),先执行UPDATE命令将LOB字段之值设为空的LOB对象,然后进行第一种改法。建议使 用替换的方法,以实现与其它字段UPDATE操作后一样的效果。
 
   4、存取时应使用由数据库JDBC驱动程序提供的LOB操作类。
 
   对于Oracle数据库,应使用oracle.sql.CLOB和oracle.sql.BLOB。不使用由数据库JDBC驱动程序提供的LOB类时,程序运行时易于出现“抽象方法调用”的错误,这是因为JDBC所定义的java.sql.Clob与 java.sql.Blob接口,其中的一些方法并未在数据库厂家提供的驱动程序中真正实现。
 
   5、存取手段与文件操作相仿。
 
   对于BLOB类型,应用InputStream/OutputStream类,此类不进行编码转换,逐个字节存取。oracle.sql.BLOB类相应提供了getBinaryStream()和getBinaryOutputStream()两个方法,前一个 方法用于读取Oracle的BLOB字段,后一个方法用于将数据写入Oracle的BLOB字段。
 
   对于CLOB类型,应用Reader/Writer类,此类进行编码转换。oracle.sql.CLOB类相应 提供了getCharacterStream()和getCharacterOutputStream()两个方法,前一个方法用于读取Oracle的 CLOB字段,后一个方法用于将数据写入Oracle的CLOB字段。
 
   需要说明的是,为了大幅提高程序执行效率,对BLOB/CLOB字段的读写操作,应该使用缓冲操作类(带 Buffered前缀),即:BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。 例程中全部使用了缓冲操作类。
上一篇下一篇

猜你喜欢

热点阅读