成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

jdbc就是這么簡(jiǎn)單

li21 / 797人閱讀

摘要:使用執(zhí)行單元測(cè)試查詢獲取連接對(duì)象根據(jù)連接對(duì)象,得到執(zhí)行語句,返回遍歷結(jié)果集查詢獲取連接對(duì)象根據(jù)連接對(duì)象,得到執(zhí)行添加影響的行數(shù),,如果大于表明操作成功。否則失敗更新成功更新失敗光標(biāo)選中方法名字,然后右鍵執(zhí)行單元測(cè)試。

文章有不當(dāng)之處,歡迎指正,如果喜歡微信閱讀,你也可以關(guān)注我的微信公眾號(hào):好好學(xué)java,獲取優(yōu)質(zhì)學(xué)習(xí)資源。
一、JDBC

JAVA Database Connectivity java 數(shù)據(jù)庫連接.

JDBC(Java DataBase Connectivity,java數(shù)據(jù)庫連接)是一種用于執(zhí)行SQL語句的Java API,可以為多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準(zhǔn),據(jù)此可以構(gòu)建更高級(jí)的工具和接口,使數(shù)據(jù)庫開發(fā)人員能夠編寫數(shù)據(jù)庫應(yīng)用程序,同時(shí),JDBC也是個(gè)商標(biāo)名。

二、為什么會(huì)出現(xiàn)JDBC

SUN公司提供的一種數(shù)據(jù)庫訪問規(guī)則、規(guī)范, 由于數(shù)據(jù)庫種類較多,并且java語言使用比較廣泛,sun公司就提供了一種規(guī)范,讓其他的數(shù)據(jù)庫提供商去實(shí)現(xiàn)底層的訪問規(guī)則。 我們的java程序只要使用sun公司提供的jdbc驅(qū)動(dòng)即可。

三、數(shù)據(jù)庫驅(qū)動(dòng)

我們安裝好數(shù)據(jù)庫之后,我們的應(yīng)用程序也是不能直接使用數(shù)據(jù)庫的,必須要通過相應(yīng)的數(shù)據(jù)庫驅(qū)動(dòng)程序,通過驅(qū)動(dòng)程序去和數(shù)據(jù)庫打交道。其實(shí)也就是數(shù)據(jù)庫廠商的JDBC接口實(shí)現(xiàn),即對(duì)Connection等接口的實(shí)現(xiàn)類的jar文件。

四、常用接口

1.Driver接口

Driver接口由數(shù)據(jù)庫廠家提供,作為java開發(fā)人員,只需要使用Driver接口就可以了。在編程中要連接數(shù)據(jù)庫,必須先裝載特定廠商的數(shù)據(jù)庫驅(qū)動(dòng)程序,不同的數(shù)據(jù)庫有不同的裝載方法。如:

裝載MySql驅(qū)動(dòng):Class.forName("com.mysql.jdbc.Driver");

裝載Oracle驅(qū)動(dòng):Class.forName("oracle.jdbc.driver.OracleDriver");

2.Connection接口

Connection與特定數(shù)據(jù)庫的連接(會(huì)話),在連接上下文中執(zhí)行sql語句并返回結(jié)果。DriverManager.getConnection(url, user, password)方法建立在JDBC URL中定義的數(shù)據(jù)庫Connection連接上。

連接MySql數(shù)據(jù)庫:Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");

連接Oracle數(shù)據(jù)庫:Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database", "user", "password");

連接SqlServer數(shù)據(jù)庫:Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port; DatabaseName=database", "user", "password");

常用方法:

createStatement():創(chuàng)建向數(shù)據(jù)庫發(fā)送sql的statement對(duì)象。

prepareStatement(sql) :創(chuàng)建向數(shù)據(jù)庫發(fā)送預(yù)編譯sql的PrepareSatement對(duì)象。

prepareCall(sql):創(chuàng)建執(zhí)行存儲(chǔ)過程的callableStatement對(duì)象。

setAutoCommit(boolean autoCommit):設(shè)置事務(wù)是否自動(dòng)提交。

commit() :在鏈接上提交事務(wù)。

rollback() :在此鏈接上回滾事務(wù)。

3.Statement接口

用于執(zhí)行靜態(tài)SQL語句并返回它所生成結(jié)果的對(duì)象。

三種Statement類:

Statement:由createStatement創(chuàng)建,用于發(fā)送簡(jiǎn)單的SQL語句(不帶參數(shù))。

PreparedStatement :繼承自Statement接口,由preparedStatement創(chuàng)建,用于發(fā)送含有一個(gè)或多個(gè)參數(shù)的SQL語句。PreparedStatement對(duì)象比Statement對(duì)象的效率更高,并且可以防止SQL注入,所以我們一般都使用PreparedStatement。

CallableStatement:繼承自PreparedStatement接口,由方法prepareCall創(chuàng)建,用于調(diào)用存儲(chǔ)過程。

常用Statement方法:

execute(String sql):運(yùn)行語句,返回是否有結(jié)果集

executeQuery(String sql):運(yùn)行select語句,返回ResultSet結(jié)果集。

executeUpdate(String sql):運(yùn)行insert/update/delete操作,返回更新的行數(shù)。

addBatch(String sql) :把多條sql語句放到一個(gè)批處理中。

executeBatch():向數(shù)據(jù)庫發(fā)送一批sql語句執(zhí)行。

4.ResultSet接口

ResultSet提供檢索不同類型字段的方法,常用的有:

getString(int index)、getString(String columnName):獲得在數(shù)據(jù)庫里是varchar、char等類型的數(shù)據(jù)對(duì)象。

getFloat(int index)、getFloat(String columnName):獲得在數(shù)據(jù)庫里是Float類型的數(shù)據(jù)對(duì)象。

getDate(int index)、getDate(String columnName):獲得在數(shù)據(jù)庫里是Date類型的數(shù)據(jù)。

getBoolean(int index)、getBoolean(String columnName):獲得在數(shù)據(jù)庫里是Boolean類型的數(shù)據(jù)。

getObject(int index)、getObject(String columnName):獲取在數(shù)據(jù)庫里任意類型的數(shù)據(jù)。

ResultSet還提供了對(duì)結(jié)果集進(jìn)行滾動(dòng)的方法:

next():移動(dòng)到下一行

Previous():移動(dòng)到前一行

absolute(int row):移動(dòng)到指定行

beforeFirst():移動(dòng)resultSet的最前面。

afterLast() :移動(dòng)到resultSet的最后面。

使用后依次關(guān)閉對(duì)象及連接:ResultSet → Statement → Connection

五、使用JDBC的基本步驟
1. 注冊(cè)驅(qū)動(dòng)
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
2. 建立連接
//DriverManager.getConnection("jdbc:mysql://localhost/test?user=SIHAI&password=SIHAI");
//2. 建立連接 參數(shù)一: 協(xié)議 + 訪問的數(shù)據(jù)庫 , 參數(shù)二: 用戶名 , 參數(shù)三: 密碼。

 conn = DriverManager.getConnection("jdbc:mysql://localhost/student", "root", "root");
3. 創(chuàng)建statement
//3. 創(chuàng)建statement , 跟數(shù)據(jù)庫打交道,一定需要這個(gè)對(duì)象
st = conn.createStatement();
4. 執(zhí)行sql ,得到ResultSet
//4. 執(zhí)行查詢 , 得到結(jié)果集
String sql = "select * from t_stu";
rs = st.executeQuery(sql);
5. 遍歷結(jié)果集
        //5. 遍歷查詢每一條記錄
         while(rs.next()){
             int id = rs.getInt("id");
             String name = rs.getString("name");
             int age = rs.getInt("age");
             System.out.println("id="+id + "===name="+name+"==age="+age);
                 
         }
6. 釋放資源
    if (rs != null) {
       try {
            rs.close();
        } catch (SQLException sqlEx) { } // ignore 
        rs = null;
    }
    
六、JDBC 工具類構(gòu)建
1. 資源釋放工作的整合
/**
     * 釋放資源
     * @param conn
     * @param st
     * @param rs
     */
    public static void release(Connection conn , Statement st , ResultSet rs){
        closeRs(rs);
        closeSt(st);
        closeConn(conn);
    }

    
    private static void closeRs(ResultSet rs){
        try {
            if(rs != null){
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            rs = null;
        }
    }
    
    private static void closeSt(Statement st){
        try {
            if(st != null){
                st.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            st = null;
        }
    }
    
    private static void closeConn(Connection conn){
        try {
            if(conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            conn = null;
        }
    }
2. 驅(qū)動(dòng)防二次注冊(cè)
/**
     * 獲取連接對(duì)象
     * @return
     */
    public static Connection getConn(){
        Connection conn = null;
        try {
            Class.forName(driverClass);
            //靜態(tài)代碼塊 ---> 類加載了,就執(zhí)行。 java.sql.DriverManager.registerDriver(new Driver());
            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            //DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
            //2. 建立連接 參數(shù)一: 協(xié)議 + 訪問的數(shù)據(jù)庫 , 參數(shù)二: 用戶名 , 參數(shù)三: 密碼。
            conn = DriverManager.getConnection(url, name, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
3. 使用properties配置文件

在src底下聲明一個(gè)文件 xxx.properties ,里面的內(nèi)容吐下:

         driverClass=com.mysql.jdbc.Driver
          url=jdbc:mysql://localhost/student
          name=root
          password=root

在工具類里面,使用靜態(tài)代碼塊,讀取屬性

static{
            try {
                //1. 創(chuàng)建一個(gè)屬性配置對(duì)象
                Properties properties = new Properties();
                InputStream is = new FileInputStream("jdbc.properties"); //對(duì)應(yīng)文件位于工程根目錄
                 
                //使用類加載器,去讀取src底下的資源文件。 后面在servlet  //對(duì)應(yīng)文件位于src目錄底下
                //InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
                //導(dǎo)入輸入流。
                properties.load(is);
                
                //讀取屬性
                driverClass = properties.getProperty("driverClass");
                url = properties.getProperty("url");
                name = properties.getProperty("name");
                password = properties.getProperty("password");
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

源代碼如下:

public class JDBCUtil {
    
    static String driverClass = null;
    static String url = null;
    static String name = null;
    static String password= null;
    
    static{
        try {
            //1. 創(chuàng)建一個(gè)屬性配置對(duì)象
            Properties properties = new Properties();
            InputStream is = new FileInputStream("jdbc.properties");
            
            //使用類加載器,去讀取src底下的資源文件。 后面在servlet
//            InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
            //導(dǎo)入輸入流。
            properties.load(is);
            
            //讀取屬性
            driverClass = properties.getProperty("driverClass");
            url = properties.getProperty("url");
            name = properties.getProperty("name");
            password = properties.getProperty("password");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 獲取連接對(duì)象
     * @return
     */
    public static Connection getConn(){
        Connection conn = null;
        try {
            Class.forName(driverClass);
            //靜態(tài)代碼塊 ---> 類加載了,就執(zhí)行。 java.sql.DriverManager.registerDriver(new Driver());
            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            //DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
            //2. 建立連接 參數(shù)一: 協(xié)議 + 訪問的數(shù)據(jù)庫 , 參數(shù)二: 用戶名 , 參數(shù)三: 密碼。
            conn = DriverManager.getConnection(url, name, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
    
    /**
     * 釋放資源
     * @param conn
     * @param st
     * @param rs
     */
    public static void release(Connection conn , Statement st , ResultSet rs){
        closeRs(rs);
        closeSt(st);
        closeConn(conn);
    }

    
    private static void closeRs(ResultSet rs){
        try {
            if(rs != null){
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            rs = null;
        }
    }
    
    private static void closeSt(Statement st){
        try {
            if(st != null){
                st.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            st = null;
        }
    }
    
    private static void closeConn(Connection conn){
        try {
            if(conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            conn = null;
        }
    }
}

?

七、數(shù)據(jù)庫的CRUD

insert操作

INSERT INTO t_stu (NAME , age) VALUES ("wangqiang",28)

INSERT INTO t_stu VALUES (NULL,"wangqiang2",28)
// 1. 獲取連接對(duì)象
conn = JDBCUtil.getConn();
// 2. 根據(jù)連接對(duì)象,得到statement
st = conn.createStatement();

//3. 執(zhí)行添加
String sql = "insert into t_stu values(null , "aobama" , 59)";
//影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);

if(result >0 ){
    System.out.println("添加成功");
}else{
    System.out.println("添加失敗");
}

delete操作

DELETE FROM t_stu WHERE id = 6
// 1. 獲取連接對(duì)象
conn = JDBCUtil.getConn();
// 2. 根據(jù)連接對(duì)象,得到statement
st = conn.createStatement();

//3. 執(zhí)行添加
String sql = "delete from t_stu where name="aobama"";
//影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);

if(result >0 ){
    System.out.println("刪除成功");
}else{
    System.out.println("刪除失敗");
}

query操作

SELECT * FROM t_stu
    // 1. 獲取連接對(duì)象
    conn = JDBCUtil.getConn();
    // 2. 根據(jù)連接對(duì)象,得到statement
    st = conn.createStatement();

    // 3. 執(zhí)行sql語句,返回ResultSet
    String sql = "select * from t_stu";
    rs = st.executeQuery(sql);

    // 4. 遍歷結(jié)果集
    while (rs.next()) {
        String name = rs.getString("name");
        int age = rs.getInt("age");

        System.out.println(name + "   " + age);
    }

update操作

UPDATE t_stu SET age = 38 WHERE id = 1;
// 1. 獲取連接對(duì)象
conn = JDBCUtil.getConn();
// 2. 根據(jù)連接對(duì)象,得到statement
st = conn.createStatement();

//3. 執(zhí)行添加
String sql = "update t_stu set age = 26 where name ="qyq"";
//影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);

if(result >0 ){
    System.out.println("更新成功");
}else{
    System.out.println("更新失敗");
}
八、使用單元測(cè)試,測(cè)試代碼
1. 定義一個(gè)類, TestXXX , 里面定義方法 testXXX.

這個(gè)命名不一定需要這樣,但是這樣的命名更容易懂得測(cè)試的意思,所以建議命名見名知意。

2. 添加junit的支持。

右鍵工程 --- add Library --- Junit --- Junit4

3. 在方法的上面加上注解 , 其實(shí)就是一個(gè)標(biāo)記。
    /**
 * 使用junit執(zhí)行單元測(cè)試
 */
public class TestDemo {

    @Test
    public void testQuery() {
        // 查詢
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 1. 獲取連接對(duì)象
            conn = JDBCUtil.getConn();
            // 2. 根據(jù)連接對(duì)象,得到statement
            st = conn.createStatement();

            // 3. 執(zhí)行sql語句,返回ResultSet
            String sql = "select * from t_stu";
            rs = st.executeQuery(sql);

            // 4. 遍歷結(jié)果集
            while (rs.next()) {
                String name = rs.getString("name");
                int age = rs.getInt("age");

                System.out.println(name + "   " + age);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.release(conn, st, rs);
        }

    }


    @Test
    public void testInsert(){
        
        // 查詢
        Connection conn = null;
        Statement st = null;
        try {
            // 1. 獲取連接對(duì)象
            conn = JDBCUtil.getConn();
            // 2. 根據(jù)連接對(duì)象,得到statement
            st = conn.createStatement();
            
            //3. 執(zhí)行添加
            String sql = "insert into t_stu values(null , "aobama" , 59)";
            //影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
            int result = st.executeUpdate(sql);
            
            if(result >0 ){
                System.out.println("添加成功");
            }else{
                System.out.println("添加失敗");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCUtil.release(conn, st);
        }

    }
    
    @Test
    public void testDelete(){
        
        // 查詢
        Connection conn = null;
        Statement st = null;
        try {
            // 1. 獲取連接對(duì)象
            conn = JDBCUtil.getConn();
            // 2. 根據(jù)連接對(duì)象,得到statement
            st = conn.createStatement();
            
            //3. 執(zhí)行添加
            String sql = "delete from t_stu where name="aobama"";
            //影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
            int result = st.executeUpdate(sql);
            
            if(result >0 ){
                System.out.println("刪除成功");
            }else{
                System.out.println("刪除失敗");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCUtil.release(conn, st);
        }

    }
    @Test
    public void testUpdate(){
        
        // 查詢
        Connection conn = null;
        Statement st = null;
        try {
            // 1. 獲取連接對(duì)象
            conn = JDBCUtil.getConn();
            // 2. 根據(jù)連接對(duì)象,得到statement
            st = conn.createStatement();
            
            //3. 執(zhí)行添加
            String sql = "update t_stu set age = 26 where name ="qyq"";
            //影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
            int result = st.executeUpdate(sql);
            
            if(result >0 ){
                System.out.println("更新成功");
            }else{
                System.out.println("更新失敗");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCUtil.release(conn, st);
        }
        
    }
}
4. 光標(biāo)選中方法名字,然后右鍵執(zhí)行單元測(cè)試。 或者是打開outline視圖, 然后選擇方法右鍵執(zhí)行。
九、Dao模式

Data Access Object 數(shù)據(jù)訪問對(duì)象

DAO(Data Access Object) 數(shù)據(jù)訪問對(duì)象是一個(gè)面向?qū)ο蟮臄?shù)據(jù)庫接口,它顯露了 Microsoft Jet 數(shù)據(jù)庫引擎(由 Microsoft Access 所使用),并允許 Visual Basic 開發(fā)者通過 ODBC 像直接連接到其他數(shù)據(jù)庫一樣,直接連接到 Access 表。DAO 最適用于單系統(tǒng)應(yīng)用程序或小范圍本地分布使用。

1. 新建一個(gè)dao的接口, 里面聲明數(shù)據(jù)庫訪問規(guī)則
    /**
    * 定義操作數(shù)據(jù)庫的方法
     */
    public interface UserDao {
    
        /**
         * 查詢所有
         */
        void findAll();
    }
2. 新建一個(gè)dao的實(shí)現(xiàn)類,具體實(shí)現(xiàn)早前定義的規(guī)則
public class UserDaoImpl implements UserDao{

        @Override
        public void findAll() {
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
            try {
                //1. 獲取連接對(duì)象
                conn = JDBCUtil.getConn();
                //2. 創(chuàng)建statement對(duì)象
                st = conn.createStatement();
                String sql = "select * from t_user";
                rs = st.executeQuery(sql);
                
                while(rs.next()){
                    String userName = rs.getString("username");
                    String password = rs.getString("password");
                    
                    System.out.println(userName+"="+password);
                }
                
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                JDBCUtil.release(conn, st, rs);
            }
        }
    
    }
3. 直接使用實(shí)現(xiàn)
    @Test
       public void testFindAll(){
           UserDao dao = new UserDaoImpl();
           dao.findAll();
       }
十、Statement安全問題
1. Statement執(zhí)行 ,其實(shí)是拼接sql語句的。 先拼接sql語句,然后在一起執(zhí)行。
String sql = "select * from t_user where username=""+ username  +"" and password=""+ password +""";

UserDao dao = new UserDaoImpl();
dao.login("admin", "100234khsdf88" or "1=1");

SELECT * FROM t_user WHERE username="admin" AND PASSWORD="100234khsdf88" or "1=1" 

//前面先拼接sql語句, 如果變量里面帶有了 數(shù)據(jù)庫的關(guān)鍵字,那么一并認(rèn)為是關(guān)鍵字。 不認(rèn)為是普通的字符串。 
rs = st.executeQuery(sql);
PrepareStatement

該對(duì)象就是替換前面的statement對(duì)象。

相比較以前的statement, 預(yù)先處理給定的sql語句,對(duì)其執(zhí)行語法檢查。 在sql語句里面使用 ? 占位符來替代后續(xù)要傳遞進(jìn)來的變量。 后面進(jìn)來的變量值,將會(huì)被看成是字符串,不會(huì)產(chǎn)生任何的關(guān)鍵字。

String sql = "insert into t_user values(null , ? , ?)";
ps = conn.prepareStatement(sql);
 
 //給占位符賦值 從左到右數(shù)過來,1 代表第一個(gè)問號(hào), 永遠(yuǎn)你是1開始。
 ps.setString(1, userName);
 ps.setString(2, password);
PreparedStatement與Statement比較

(1) 使用PreparedStatement,代碼的可讀性和可維護(hù)性比Statement高。

(2) PreparedStatement 能最大可能提高性能。

DBServer會(huì)對(duì)預(yù)編譯語句提供性能優(yōu)化。因?yàn)轭A(yù)編譯語句有可能被重復(fù)調(diào)用,所以語句在被DBServer的編譯器編譯后的執(zhí)行代碼被緩存下來,那么下次調(diào)用時(shí)只要是相同的預(yù)編譯語句就不需要編譯,只要將參數(shù)直接傳入編譯過的語句執(zhí)行代碼中就會(huì)得到執(zhí)行。

在statement語句中,即使是相同操作但因?yàn)閿?shù)據(jù)內(nèi)容不一樣,所以整個(gè)語句本身不能匹配,沒有緩存語句的意義。事實(shí)是沒有數(shù)據(jù)庫會(huì)對(duì)普通語句編譯后的執(zhí)行代碼緩存。這樣每執(zhí)行一次都要對(duì)傳入的語句編譯一次。

(3) PreparedStatement能保證安全性,但 Statement有sql注入等安全問題。

十一、數(shù)據(jù)庫事務(wù)

1. 概述

在數(shù)據(jù)庫中,所謂事務(wù)是指一組邏輯操作單元,使數(shù)據(jù)從一種狀態(tài)變換到另一種狀態(tài)。

為確保數(shù)據(jù)庫中數(shù)據(jù)的一致性,數(shù)據(jù)的操縱應(yīng)當(dāng)是離散的成組的邏輯單元:當(dāng)它全部完成時(shí),數(shù)據(jù)的一致性可以保持,而當(dāng)這個(gè)單元中的一部分操作失敗,整個(gè)事務(wù)應(yīng)全部視為錯(cuò)誤,所有從起始點(diǎn)以后的操作應(yīng)全部回退到開始狀態(tài)。

事務(wù)的操作:先定義開始一個(gè)事務(wù),然后對(duì)數(shù)據(jù)作修改操作,這時(shí)如果提交(COMMIT),這些修改就永久地保存下來,如果回退(ROLLBACK),數(shù)據(jù)庫管理系統(tǒng)將放棄您所作的所有修改而回到開始事務(wù)時(shí)的狀態(tài)。

2. 事務(wù)的ACID屬性

2.1 原子性(Atomicity)

原子性是指事務(wù)是一個(gè)不可分割的工作單位,事務(wù)中的操作要么都發(fā)生,要么都不發(fā)生。

2.2 一致性(Consistency)

事務(wù)必須使數(shù)據(jù)庫從一個(gè)一致性狀態(tài)變換到另外一個(gè)一致性狀態(tài)。(數(shù)據(jù)不被破壞)

2.3 隔離性(Isolation)

事務(wù)的隔離性是指一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾,即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)并發(fā)的其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾。

2.4 持久性(Durability)

持久性是指一個(gè)事務(wù)一旦被提交,它對(duì)數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久性的,接下來的其他操作和數(shù)據(jù)庫故障不應(yīng)該對(duì)其有任何影響。

3. JDBC 事務(wù)處理

在JDBC中,事務(wù)默認(rèn)是自動(dòng)提交的,每次執(zhí)行一個(gè) SQL 語句時(shí),如果執(zhí)行成功,就會(huì)向數(shù)據(jù)庫自動(dòng)提交,而不能回滾。

為了讓多個(gè) SQL 語句作為一個(gè)事務(wù)執(zhí)行,需調(diào)用 Connection 對(duì)象的 setAutoCommit(false); 以取消自動(dòng)提交事務(wù):

conn.setAutoCommit(false);

在所有的 SQL 語句都成功執(zhí)行后,調(diào)用 commit(); 方法提交事務(wù)

conn.commit();

在出現(xiàn)異常時(shí),調(diào)用 rollback(); 方法回滾事務(wù),一般再catch模塊中執(zhí)行回滾操作。

conn.rollback();

可以通過Connection的getAutoCommit()方法來獲得當(dāng)前事務(wù)的提交方式。

注意:在MySQL中的數(shù)據(jù)庫存儲(chǔ)引擎InnoDB支持事務(wù),MyISAM不支持事務(wù)。

十二、批量處理JDBC語句

1. 概述

當(dāng)需要批量插入或者更新記錄時(shí)??梢圆捎肑ava的批量更新機(jī)制,這一機(jī)制允許多條語句一次性提交給數(shù)據(jù)庫批量處理。通常情況下比多帶帶提交處理更有效率。

JDBC的批量處理語句包括下面兩個(gè)方法:

addBatch(String):添加需要批量處理的SQL語句或是參數(shù);

executeBatch();執(zhí)行批量處理語句;

通常我們會(huì)遇到兩種批量執(zhí)行SQL語句的情況:

多條SQL語句的批量處理;

一個(gè)SQL語句的批量傳參;

2. Statement批量處理

Statement sm = conn.createStatement();
sm.addBatch(sql1);
sm.addBatch(sql2);
...
//批量處理
sm.executeBatch()
//清除sm中積攢的參數(shù)列表
sm.clearBatch();

3. PreparedStatement批量傳參

preparedStatement ps = conn.preparedStatement(sql);
for(int i=1;i<100000;i++){
    ps.setInt(1, i);
    ps.setString(2, "name"+i);
    ps.setString(3, "email"+i);
    ps.addBatch();
    if((i+1)%1000==0){
        //批量處理
        ps.executeBatch();
        //清空ps中積攢的sql
        ps.clearBatch();
    }
}

注意:MySQL不支持批量處理。

批量處理應(yīng)該設(shè)置一個(gè)上限,當(dāng)批量處理列表中的sql累積到一定數(shù)量后,就應(yīng)該執(zhí)行,并在執(zhí)行完成后,清空批量列表。

一般在excel導(dǎo)入數(shù)據(jù)的時(shí)候會(huì)用到批處理。

十三、使用 JDBC 處理元數(shù)據(jù)

1. 概述

Java 通過JDBC獲得連接以后,得到一個(gè)Connection 對(duì)象,可以從這個(gè)對(duì)象獲得有關(guān)數(shù)據(jù)庫管理系統(tǒng)的各種信息,包括數(shù)據(jù)庫中的各個(gè)表,表中的各個(gè)列,數(shù)據(jù)類型,觸發(fā)器,存儲(chǔ)過程等各方面的信息。根據(jù)這些信息,JDBC可以訪問一個(gè)實(shí)現(xiàn)事先并不了解的數(shù)據(jù)庫。

獲取這些信息的方法都是在DatabaseMetaData類的對(duì)象上實(shí)現(xiàn)的,而DataBaseMetaData對(duì)象是在Connection對(duì)象上獲得的。

2. 獲取數(shù)據(jù)庫元數(shù)據(jù)

DatabaseMetaData 類中提供了許多方法用于獲得數(shù)據(jù)源的各種信息,通過這些方法可以非常詳細(xì)的了解數(shù)據(jù)庫的信息:

getURL():返回一個(gè)String類對(duì)象,代表數(shù)據(jù)庫的URL。

getUserName():返回連接當(dāng)前數(shù)據(jù)庫管理系統(tǒng)的用戶名。

isReadOnly():返回一個(gè)boolean值,指示數(shù)據(jù)庫是否只允許讀操作。

getDatabaseProductName():返回?cái)?shù)據(jù)庫的產(chǎn)品名稱。

getDatabaseProductVersion():返回?cái)?shù)據(jù)庫的版本號(hào)。

getDriverName():返回驅(qū)動(dòng)驅(qū)動(dòng)程序的名稱。

getDriverVersion():返回驅(qū)動(dòng)程序的版本號(hào)。

3. ResultSetMetaData

可用于獲取關(guān)于 ResultSet 對(duì)象中列的類型和屬性信息的對(duì)象:

getColumnName(int column):獲取指定列的名稱

getColumnCount():返回當(dāng)前 ResultSet 對(duì)象中的列數(shù)。

getColumnTypeName(int column):檢索指定列的數(shù)據(jù)庫特定的類型名稱。

getColumnDisplaySize(int column):指示指定列的最大標(biāo)準(zhǔn)寬度,以字符為單位。

isNullable(int column):指示指定列中的值是否可以為 null。

isAutoIncrement(int column):指示是否自動(dòng)為指定列進(jìn)行編號(hào),這樣這些列仍然是只讀的。

十四、創(chuàng)建可滾動(dòng)、更新的記錄集

1. Statement

Statement stmt = conn.createStatement(type,concurrency);

2. PreparedStatement

PreparedStatement stmt = conn.prepareStatement(sql,type,concurrency);

type說明:

ResultSet的Type 說明
TYPE_FORWARD_ONLY 結(jié)果集不能滾動(dòng),只可向前滾動(dòng)
TYPE_SCROLL_INSENSITIVE 雙向滾動(dòng),但不及時(shí)更新,就是如果數(shù)據(jù)庫里的數(shù)據(jù)修改過,并不在ResultSet中反應(yīng)出來
TYPE_SCROLL_SENSITIVE 雙向滾動(dòng),并及時(shí)跟蹤數(shù)據(jù)庫的更新,以便更改ResultSet中的數(shù)據(jù)

Concurrency(并發(fā)類型)說明:

ResultSet的Concurrency(并發(fā)類型) 說明
CONCUR_READ_ONLY 結(jié)果集不可用于更新數(shù)據(jù)庫
CONCUR_UPDATABLE 結(jié)果集可以用于更新數(shù)據(jù)庫

3. ResultSet滾動(dòng)的結(jié)果集使用

First: 將指針移動(dòng)到此 ResultSet 對(duì)象的第一行
Last: 將指針移動(dòng)到此 ResultSet 對(duì)象的最后一行
beforeFirst: 將指針移動(dòng)到此 ResultSet 對(duì)象的開頭,正好位于第一行之前
afterLast: 將指針移動(dòng)到此 ResultSet 對(duì)象的末尾,正好位于最后一行之后
isFirst: 檢索指針是否位于此 ResultSet 對(duì)象的第一行
isLast: 檢索指針是否位于此 ResultSet 對(duì)象的最后一行
isBeforeFirst: 檢索指針是否位于此 ResultSet 對(duì)象的第一行之前
isAfterLast: 檢索指針是否位于此 ResultSet 對(duì)象的最后一行之后
Relative: 按相對(duì)行數(shù)(或正或負(fù))移動(dòng)指針
Next: 將指針從當(dāng)前位置下移一行
Previous: 將指針移動(dòng)到此 ResultSet 對(duì)象的上一行
Absolute: 將指針移動(dòng)到此 ResultSet 對(duì)象的給定行編號(hào)

如:

rs.absolute(80); //將指針移動(dòng)到ResultSet 對(duì)象的第80行記錄。

注意:該特性對(duì)Oralce數(shù)據(jù)有效。但是在Mysql數(shù)據(jù)庫中無效,Mysql只支持TYPE_SCROLL_INSENSITIVE,CONCUR_READ_ONLY

十五、JDBC連接池

1. 為什么要使用JDBC連接池

普通的JDBC數(shù)據(jù)庫連接使用 DriverManager 來獲取,每次向數(shù)據(jù)庫建立連接的時(shí)候都要將 Connection 加載到內(nèi)存中,再驗(yàn)證用戶名和密碼。需要數(shù)據(jù)庫連接的時(shí)候,就向數(shù)據(jù)庫要求一個(gè),執(zhí)行完成后再斷開連接。這樣的方式將會(huì)消耗大量的資源和時(shí)間。數(shù)據(jù)庫的連接資源并沒有得到很好的重復(fù)利用.若同時(shí)有幾百人甚至幾千人在線,頻繁的進(jìn)行數(shù)據(jù)庫連接操作將占用很多的系統(tǒng)資源,嚴(yán)重的甚至?xí)斐煞?wù)器的崩潰。

對(duì)于每一次數(shù)據(jù)庫連接,使用完后都得斷開。否則,如果程序出現(xiàn)異常而未能關(guān)閉,將會(huì)導(dǎo)致數(shù)據(jù)庫系統(tǒng)中的內(nèi)存泄漏,最終將導(dǎo)致重啟數(shù)據(jù)庫。

這種開發(fā)不能控制被創(chuàng)建的連接對(duì)象數(shù),系統(tǒng)資源會(huì)被毫無顧及的分配出去,如連接過多,也可能導(dǎo)致內(nèi)存泄漏,服務(wù)器崩潰。

為解決傳統(tǒng)開發(fā)中的數(shù)據(jù)庫連接問題,可以采用數(shù)據(jù)庫連接池技術(shù)。

2. 數(shù)據(jù)庫連接池(connection pool)

數(shù)據(jù)庫連接池的基本思想就是為數(shù)據(jù)庫連接建立一個(gè)“緩沖池”。預(yù)先在緩沖池中放入一定數(shù)量的連接,當(dāng)需要建立數(shù)據(jù)庫連接時(shí),只需從“緩沖池”中取出一個(gè),使用完畢之后再放回去。

數(shù)據(jù)庫連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫連接,而不是重新建立一個(gè)。

數(shù)據(jù)庫連接池在初始化時(shí)將創(chuàng)建一定數(shù)量的數(shù)據(jù)庫連接放到連接池中,這些數(shù)據(jù)庫連接的數(shù)量是由最小數(shù)據(jù)庫連接數(shù)來設(shè)定的。無論這些數(shù)據(jù)庫連接是否被使用,連接池都將一直保證至少擁有這么多的連接數(shù)量。連接池的最大數(shù)據(jù)庫連接數(shù)量限定了這個(gè)連接池能占有的最大連接數(shù),當(dāng)應(yīng)用程序向連接池請(qǐng)求的連接數(shù)超過最大連接數(shù)量時(shí),這些請(qǐng)求將被加入到等待隊(duì)列中。

3. 數(shù)據(jù)庫連接池工作原理

4. 使用數(shù)據(jù)庫連接池的優(yōu)點(diǎn)

(1)資源重用:

由于數(shù)據(jù)庫連接得以重用,避免了頻繁創(chuàng)建,釋放連接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上,另一方面也增加了系統(tǒng)運(yùn)行環(huán)境的平穩(wěn)性。

(2)更快的系統(tǒng)反應(yīng)速度

數(shù)據(jù)庫連接池在初始化過程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫連接置于連接池中備用。此時(shí)連接的初始化工作均已完成。對(duì)于業(yè)務(wù)請(qǐng)求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫連接初始化和釋放過程的時(shí)間開銷,從而減少了系統(tǒng)的響應(yīng)時(shí)間。

(3)新的資源分配手段

對(duì)于多應(yīng)用共享同一數(shù)據(jù)庫的系統(tǒng)而言,可在應(yīng)用層通過數(shù)據(jù)庫連接池的配置,實(shí)現(xiàn)某一應(yīng)用最大可用數(shù)據(jù)庫連接數(shù)的限制,避免某一應(yīng)用獨(dú)占所有的數(shù)據(jù)庫資源。

(4)統(tǒng)一的連接管理,避免數(shù)據(jù)庫連接泄露
在較為完善的數(shù)據(jù)庫連接池實(shí)現(xiàn)中,可根據(jù)預(yù)先的占用超時(shí)設(shè)定,強(qiáng)制回收被占用連接,從而避免了常規(guī)數(shù)據(jù)庫連接操作中可能出現(xiàn)的資源泄露。

5. 常用數(shù)據(jù)庫連接池介紹

JDBC 的數(shù)據(jù)庫連接池使用 javax.sql.DataSource 來表示,DataSource 只是一個(gè)接口,該接口通常由服務(wù)器(Weblogic, WebSphere, Tomcat)提供實(shí)現(xiàn),也有一些開源組織提供實(shí)現(xiàn),如:

DBCP 數(shù)據(jù)庫連接池

C3P0 數(shù)據(jù)庫連接池

Proxpool 數(shù)據(jù)庫連接池

其中,DBCP和C3P0用得比較多。

Tomcat 在 7.0 以前的版本都是使用 commons-dbcp 做為連接池的實(shí)現(xiàn)。

數(shù)據(jù)源和數(shù)據(jù)庫連接不同,數(shù)據(jù)源無需創(chuàng)建多個(gè),它是產(chǎn)生數(shù)據(jù)庫連接的工廠,因此整個(gè)應(yīng)用只需要一個(gè)數(shù)據(jù)源即可。

當(dāng)數(shù)據(jù)庫訪問結(jié)束后,程序還是像以前一樣關(guān)閉數(shù)據(jù)庫連接:conn.close(); 但它并沒有關(guān)閉數(shù)據(jù)庫的物理連接,它僅僅把數(shù)據(jù)庫連接釋放,歸還給了數(shù)據(jù)庫連接池。

大概基本的就是這么多了,希望能夠幫助到大家,有問題可以交流溝通。

?

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76603.html

相關(guān)文章

  • Java3y文章目錄導(dǎo)航

    摘要:前言由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個(gè)博客導(dǎo)航。 前言 由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個(gè)博客導(dǎo)航。 由于更新比較頻繁,因此隔一段時(shí)間才會(huì)更新目錄導(dǎo)航哦~想要獲取最新原創(chuàng)的技術(shù)文章歡迎關(guān)注我的公眾號(hào):Java3y Java3y文章目錄導(dǎo)航 Java基礎(chǔ) 泛型就這么簡(jiǎn)單 注解就這么簡(jiǎn)單 Druid數(shù)據(jù)庫連接池...

    KevinYan 評(píng)論0 收藏0
  • Spring【DAO模塊】就是這么簡(jiǎn)單

    摘要:連接對(duì)象執(zhí)行命令對(duì)象執(zhí)行關(guān)閉值得注意的是,對(duì)數(shù)據(jù)庫連接池是有很好的支持的。給我們提供了事務(wù)的管理器類,事務(wù)管理器類又分為兩種,因?yàn)榈氖聞?wù)和的事務(wù)是不一樣的。 前言 上一篇Spring博文主要講解了如何使用Spring來實(shí)現(xiàn)AOP編程,本博文主要講解Spring的DAO模塊對(duì)JDBC的支持,以及Spring對(duì)事務(wù)的控制... 對(duì)于JDBC而言,我們肯定不會(huì)陌生,我們?cè)诔鯇W(xué)的時(shí)候肯定寫過非...

    NSFish 評(píng)論0 收藏0
  • SpringDataJPA入門就這么簡(jiǎn)單

    摘要:一入門在上次學(xué)的時(shí)候,那時(shí)候的教程就已經(jīng)涉及到了一點(diǎn)的知識(shí)了。入門只是中的一個(gè)子模塊是一套標(biāo)準(zhǔn)接口,而是的實(shí)現(xiàn)底層默認(rèn)實(shí)現(xiàn)是使用的首個(gè)接口就是,它是一個(gè)標(biāo)記接口。這也導(dǎo)致了我出現(xiàn)這個(gè)錯(cuò)誤的原因。 一、SpringData入門 在上次學(xué)SpringBoot的時(shí)候,那時(shí)候的教程就已經(jīng)涉及到了一點(diǎn)SpringData JPA的知識(shí)了。當(dāng)時(shí)還是第一次見,覺得也沒什么大不了,就是封裝了Hiber...

    MasonEast 評(píng)論0 收藏0
  • application.properties數(shù)據(jù)庫敏感信息加密這么簡(jiǎn)單?

    摘要:前些天就有了一個(gè)滿足漏洞檢測(cè)的需求,想要把數(shù)據(jù)庫的明文敏感信息加密,其實(shí)也就是密碼加密,所以也就有了這篇文章,我的項(xiàng)目是結(jié)構(gòu),修改其實(shí)也挺簡(jiǎn)單,廢話少說,上代碼。所以您有什么更好的加密方法歡迎留言 寫在前面 俗話說:顧客是上帝,身為程序員的我有時(shí)會(huì)直接對(duì)接客戶方提出的需求,畢竟我處在提供服務(wù)的一方,所以我也會(huì)盡量的滿足臨時(shí)的要求。前些天就有了一個(gè)滿足漏洞檢測(cè)的需求,想要把數(shù)據(jù)庫的明文敏...

    Lycheeee 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<