JDBC高级特性

1.如何使用JDBC事务

(1)事务的四个特性:

一.原子性(Atomicity)

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

二.一致性(Consistency)

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

三.隔离性(Isolation)

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

四.持久性(Durability)

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

在JDBC中,事务默认是自动提交的,每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。

(2)取消JDBC默认的自动提交方式,改为手动提交

conn.setAutoCommit(false);

(3)多有JDBC操作都执行完毕后提交事务

conn.commit();

(4)有一个JDBC操作发生问题就回滚事务

conn.rollback();

(5)可以通过设置事务的保存点来灵活的进行控制(Savepoint).

Savepoint是java.sql包的一个接口,可以在回滚事务时引用当前事务中的保存点,将事务回滚到保存点,在该保存点之后所做的全部操作都将被撤销。

conn.setSavepoint();

 2.JDBC批量操作

 1 package cn.com.demo;
 2 import java.io.BufferedReader;
 3 import java.io.File;
 4 import java.io.FileReader;
 5 import java.sql.Connection;
 6 import java.sql.PreparedStatement;
 7 import java.sql.SQLException;
 8 import java.sql.Timestamp;
 9 import java.util.ArrayList;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.regex.Pattern;
13 public class TestBatch {
14  private Connection conn = null;
15  private PreparedStatement pstmt = null;
16  public static void main(String[] args) {
17   TestBatch tb = new TestBatch();
18   List<String> list = tb.readFile();
19   Iterator<String> iter = list.iterator();
20   while (iter.hasNext()) {
21    System.out.println(iter.next() + "\t");
22   }
23   tb.updateSms(list);
24  }
25  public void updateSms(List<String> list) {
26   int i = 0;
27   long startTime = System.currentTimeMillis();
28   try {
29    String sql = "insert into sendsms(name,sourcetel,desttel,senddate) values(?,?,?,?)";
30    conn = DaoFactory.getConnection();
31    conn.setAutoCommit(false);// 设置事务手动提交
32    pstmt = conn.prepareStatement(sql);
33    for (String tel : list) { // 循环获取手机号
34     pstmt.setString(1, "张苏纳");
35     pstmt.setString(2, "15026470454");
36     pstmt.setString(3, tel);
37     pstmt.setTimestamp(4,
38       new Timestamp(new java.util.Date().getTime()));
39     pstmt.addBatch();// 加入缓存
40     i++;
41     if (i % 10000 == 0) {// 10000保存一次
42      pstmt.executeBatch();// 批量处理
43      pstmt.clearBatch();// 清空pstmt中积攒的sql
44     }
45     // pstmt.executeUpdate();// 执行保存
46    }
47    pstmt.executeBatch();// 执行所有的sql语句
48    conn.commit(); // 提交事务
49   } catch (Exception e) {
50    try {
51     conn.rollback();
52    } catch (SQLException e1) {
53     e1.printStackTrace();
54    }
55    e.printStackTrace();
56   } finally {
57    DaoFactory.closeAll(null, pstmt, conn);
58   }
59   long endTime = System.currentTimeMillis();
60   long time = (endTime - startTime) / 1000;
61   System.out.println("耗时" + time + "秒。");
62  }
63  // 读取号码文件
64  public List<String> readFile() {
65   List<String> list = new ArrayList<String>();
66   File file = new File("E:" + File.separator + "测试.txt"); // 100000个手机号
67   try {
68    FileReader fileReader = new FileReader(file);
69    BufferedReader bufferedReader = new BufferedReader(fileReader);
70    while (bufferedReader.ready()) {
71     String tel = bufferedReader.readLine();
72     if (tel.length() > 0) {
73      if (tel.contains(" ")) {
74       tel = tel.replace(" ", "");
75      }
76      // 验证手机号
77      if (!Pattern.compile("^1[358]\\d{9}$").matcher(tel)
78        .matches()) {
79       System.out.println("手机号码格式不正确" + tel);
80       continue;
81      }
82      list.add(tel);
83     }
84    }
85    bufferedReader.close();
86    fileReader.close();
87   } catch (Exception e) {
88    e.printStackTrace();
89    e.getMessage();
90   }
91   return list;
92  }
93 }
批量操作

 

3.DAO模式(即数据存取对象)

使用DAO模式进行项目开发主要由以下两个好处:

(1)隔离了业务逻辑代码和数据访问代码,分工明确,降低耦合度,提高可重用性

(2)采用面向接口编程,提高了项目的可扩展和可维护性。

一个典型的DAO模式主要由一下几个部分组成:

(1)一个工厂类,主要负责创建和关闭Connection对象

(2)DAO接口,定义业务方法

(3)实体类,储存和传递数据

4.DAO模式扩展

package cn.com.dao;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

public class BaseDAO<T> {
    private final String driver = "com.mysql.jdbc.Driver";
    private final String url = "jdbc:mysql://localhost:3306/mytest";
    private final String user = "root";
    private final String password = "";

    // 获取连接
    public Connection getConnection() {
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, user, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    // 执行增删改的方法
    public int executeUpdate(String sql, Object[] params) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        int count = 0;
        try {
            conn = this.getConnection();
            pstmt = conn.prepareStatement(sql);
            setParams(pstmt, params);
            count = pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.closeAll(null, pstmt, conn);
        }
        return count;
    }

    /**
     * 泛型查询
     * 
     * @param sql
     *            SQL语句
     * @param args
     *            查询语句的参数
     * @param className
     *            类的完全限定名
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<T> generalSearch(String sql, Object[] args, String className) {
        // 存储返回的集合对象
        List<T> list = new ArrayList<T>();
        Connection conn = this.getConnection();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            // 使用反射获取类的相关信息
            Class<T> clazz = (Class<T>) Class.forName(className);
            Field[] fields = clazz.getDeclaredFields();
            Method method = null;
            pstmt = conn.prepareStatement(sql);
            setParams(pstmt, args);
            rs = pstmt.executeQuery();
            ResultSetMetaData resmd = null;
            // 获取结果集的元素据
            resmd = rs.getMetaData();
            // 获取一共多少列
            int columnCount = resmd.getColumnCount();
            while (rs.next()) {
                T obj = clazz.newInstance(); // 创建一个新对象
                for (int i = 1; i <= columnCount; i++) {
                    String cname = resmd.getColumnName(i); // 获取每一列的名称
                    int ctype = resmd.getColumnType(i);// 获取每一列的类型
                    for (Field field : fields) { // 循环实体类的列
                        if (cname.equals(field.getName())) { // 如果列名和属性名相同
                            // 封装数据
                            String firstLetter = field.getName()
                                    .substring(0, 1).toUpperCase();
                            String methodName = "set" + firstLetter
                                    + field.getName().substring(1);
                            // 如果列时整型的
                            if (ctype == Types.INTEGER) {
                                method = clazz.getMethod(methodName,
                                        Integer.class);
                                method.invoke(obj, rs.getInt(i));
                            } else if (ctype == Types.VARCHAR) {
                                method = clazz.getMethod(methodName,
                                        String.class);
                                method.invoke(obj, rs.getString(i));
                            } else if (ctype == Types.TIMESTAMP) {
                                method = clazz
                                        .getMethod(methodName, Date.class);
                                method.invoke(obj, rs.getDate(i));
                            } else if (ctype == Types.NUMERIC) {
                                method = clazz.getMethod(methodName,
                                        Double.class);
                                method.invoke(obj, rs.getDouble(i));
                            }
                        }
                    }
                }
                list.add(obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.closeAll(rs, pstmt, conn);
        }
        return list;
    }

    // 设置参数的方法
    public void setParams(PreparedStatement ps, Object[] params) {
        if (params == null) {
            return;
        }
        for (int i = 0; i < params.length; i++) {
            try {
                ps.setObject(i + 1, params[i]);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    // 释放资源
    public void closeAll(ResultSet rs, Statement stmt, Connection conn) {
        try {
            if (rs != null)
                rs.close();
            if (stmt != null)
                stmt.close();
            if (conn != null)
                conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
DAO模式扩展

5.JDBC元数据

JDBC到了版本3以后加入了元数据的功能,有了JDB元数据就可以很方便的获取数据库对相关的信息。

 1 package cn.com.demo;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 
 8 import com.mysql.jdbc.DatabaseMetaData;
 9 import com.mysql.jdbc.ResultSetMetaData;
10 
11 public class MetaDataTest {
12     public static void main(String[] args) {
13         testDatabaseMetaData();
14         String sql = "select * from userinfo";
15         testResultSetMetaData(sql);
16     }
17 
18     /**
19      * DatabaseMetaData接口可以获取关于数据库的整体综合信息,譬如数据库产品的名称等等。
20      */
21     public static void testDatabaseMetaData() {
22         BaseDAO base = new BaseDAO();
23         Connection conn = base.getConnection();
24         try {
25             DatabaseMetaData dmd = (DatabaseMetaData) conn.getMetaData();
26             String pname = dmd.getDatabaseProductName();// 获取数据库产品名称
27             String driverName = dmd.getDriverName();// 获取驱动名称
28             String pversion = dmd.getDatabaseProductVersion();// 获取驱动版本号
29             int isolation = dmd.getDefaultTransactionIsolation();// 获取默认隔离级别
30             System.out.println("数据库产品:" + "\n" + pname + "驱动名称:" + "\n"
31                     + driverName + "\n" + "驱动版本:" + "\n" + pversion + "隔离级别:"
32                     + isolation);
33         } catch (SQLException e) {
34             e.printStackTrace();
35         }
36     }
37 
38     /**
39      * ResultSetMetaData接口可以获取关于ResultSet对象中列的类型和属性的信息。
40      * 因为结果集是从数据库表中查询到的一个二维表,所以可以获得这个表格的列的数量,列的类型,列的名称等信息。
41      * 
42      * @param sql
43      */
44     public static void testResultSetMetaData(String sql) {
45         BaseDAO base = new BaseDAO();
46         Connection conn = base.getConnection();
47         PreparedStatement pstmt = null;
48         ResultSet rs = null;
49         try {
50             pstmt = conn.prepareStatement(sql);
51             rs = pstmt.executeQuery();
52             ResultSetMetaData resmd = null;
53             resmd = (ResultSetMetaData) rs.getMetaData();// 获取结果集的元数据
54             int columnCount = resmd.getColumnCount();// 获取一共有多少列
55             for (int i = 0; i < columnCount; i++) {
56                 String cname = resmd.getColumnName(i);// 获取每一列的名称
57                 int ctype = resmd.getColumnType(i);// 获取每一列的类型
58                 String tname = resmd.getColumnTypeName(i);// 获取类型名称
59                 System.out.println("列明:" + cname + "\t列类型名称:" + tname
60                         + "\t列类型:" + ctype);
61             }
62         } catch (SQLException e) {
63             e.printStackTrace();
64         } finally {
65             DaoFactory.closeAll(rs, pstmt, conn);
66         }
67     }
68 
69 }
JDBC元数据

 数据库连接

 1 package cn.com.util;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.ResultSet;
 6 import java.sql.Statement;
 7 
 8 public class DaoFactory {
 9     private static String driver = "oracle.jdbc.driver.OracleDriver";
10     private static String url = "jdbc:oracle:thin:@localhost:1521:orcl";
11     private static String user = "scott";
12     private static String password = "tiger";
13 
14     public static Connection getConnection() {
15         Connection conn = null;
16         try {
17             Class.forName(driver);
18             conn = DriverManager.getConnection(url, user, password);
19         } catch (Exception e) {
20             e.printStackTrace();
21         }
22         return conn;
23     }
24 
25     public static void closeAll(ResultSet rs, Statement stmt, Connection conn) {
26         try {
27             if (rs != null)
28                 rs.close();
29             if (stmt != null)
30                 stmt.close();
31             if (conn != null)
32                 conn.close();
33         } catch (Exception e) {
34             e.printStackTrace();
35         }
36     }
37 }
数据库连接

 

6.读写二进制文件

 1 package cn.com.util;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileOutputStream;
 6 import java.io.InputStream;
 7 import java.sql.Blob;
 8 import java.sql.Connection;
 9 import java.sql.PreparedStatement;
10 import java.sql.ResultSet;
11 
12 /**
13  * 读写二进制文件
14  * 
15  * @author wangxiaocong
16  * 
17  */
18 public class BlobTest {
19     public static void main(String[] args) {
20         //writeBlob();
21          readerBlob();
22     }
23 
24     // 写入二进制文件
25     public static void writeBlob() {
26         InputStream is = null;
27         Connection conn = null;
28         PreparedStatement pstmt = null;
29         try {
30             conn = DaoFactory.getConnection();
31             String sql = "update stuinfo set file_data = ?,file_name = ? where id = 3 ";
32             pstmt = conn.prepareStatement(sql);
33             File f = new File("D:" + File.separator + "蓝波 - 迎着风.mp3");
34             is = new FileInputStream(f);
35             // 设置二进制流参数
36             pstmt.setBinaryStream(1, is, f.length());
37             pstmt.setString(2, f.getName());
38             int result = pstmt.executeUpdate();
39             if (result == 1) {
40                 System.out.println("添加音乐成功");
41             }
42         } catch (Exception e) {
43             e.printStackTrace();
44         } finally {
45             DaoFactory.closeAll(null, pstmt, conn);
46         }
47     }
48 
49     // 读取二进制文件
50     public static void readerBlob() {
51         Connection conn = null;
52         PreparedStatement pstmt = null;
53         ResultSet rs = null;
54         FileOutputStream out = null;
55         try {
56             conn = DaoFactory.getConnection();
57             String sql = "select file_name,file_data from stuinfo where id = 3";
58             pstmt = conn.prepareStatement(sql);
59             rs = pstmt.executeQuery();
60             rs.next();
61             String fileName = rs.getString(1);
62             System.out.println(fileName);
63             Blob blob = rs.getBlob(2);
64             out = new FileOutputStream("D:" + File.separator
65                     + new File(fileName).getName());
66             out.write(blob.getBytes(1
67                     , (int) blob.length()));
68             out.close();
69             String[] cmdStrings = { "F:\\酷狗音乐\\PPStream\\GeePlayer\\3.0.40.3591\\GeePlayer.exe",
70                     "D:" + File.separator + fileName };
71             Runtime.getRuntime().exec(cmdStrings);// 打开播放器
72         } catch (Exception e) {
73             e.printStackTrace();
74         } finally {
75             DaoFactory.closeAll(rs, pstmt, conn);
76         }
77     }
78 }
读写二进制文件

7.读写大段文本

 1 package cn.com.util;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.File;
 5 import java.io.FileReader;
 6 import java.io.FileWriter;
 7 import java.io.Reader;
 8 import java.sql.Connection;
 9 import java.sql.PreparedStatement;
10 import java.sql.ResultSet;
11 /**
12  * 读写大段文本
13  * @author wangxiaocong
14  *
15  */
16 public class ClobTest {
17     private static Connection conn = null;
18     private static PreparedStatement pstmt = null;
19     private static ResultSet rs = null;
20 
21     public static void main(String[] args) {
22      //writeText();
23      readText();
24     }
25 
26     // 写入大文本
27     public static void writeText() {
28         try {
29             conn = DaoFactory.getConnection();
30             String sql = "update stuinfo set resume = ? where id = 3";
31             pstmt = conn.prepareStatement(sql);
32             File file = new File("src/resume.txt");
33             Reader reader = new BufferedReader(new FileReader(file));
34             pstmt.setCharacterStream(1, reader);
35             int i = pstmt.executeUpdate();
36             reader.close();
37             System.out.println(i);
38         } catch (Exception e) {
39             e.printStackTrace();
40         } finally {
41             DaoFactory.closeAll(rs, pstmt, conn);
42         }
43     }
44 
45     // 读取大文本
46     public static void readText() {
47         try {
48             conn = DaoFactory.getConnection();
49             String sql = "select * from stuinfo where id = 3";
50             pstmt = conn.prepareStatement(sql);
51             rs = pstmt.executeQuery();
52             if (rs.next()) {
53                 Reader reader = rs.getCharacterStream("resume");
54                 char buff[] = new char[1024];
55                 int len = 0;
56                 FileWriter writer = new FileWriter("D:"+File.separator+"resume.txt");
57                 while ((len = reader.read(buff)) > 0) {
58                     System.out.println(new String(buff, 0, len));
59                     writer.write(buff, 0, len);
60                 }
61                 writer.close();
62                 reader.close();
63             }
64         } catch (Exception e) {
65             e.printStackTrace();
66         } finally {
67             DaoFactory.closeAll(rs, pstmt, conn);
68         }
69     }
70 }
读写大段文本

 

posted @ 2017-12-04 21:52  WangXiaoCong  阅读(793)  评论(0编辑  收藏  举报