基本的JDBC以及CRUD/Transaction基本操作

Posted 幽幽子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基本的JDBC以及CRUD/Transaction基本操作相关的知识,希望对你有一定的参考价值。

  先上依赖:

        <!-- mysql start -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!-- mysql end -->
        <!-- junit start -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- junit end -->
        <!-- log start -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
        <!-- log end -->

基本的JDBCUtil(DBManager):

/**
 * JDBCUtil with mysql-connector-java-5.1.38.jar<br>
 * 
 * @author Changjiang.Chen
 *
 */
public class JDBCUtil {

    private static final Log log = LogFactory.getLog(JDBCUtil.class);
    private static String URL;
    private static String USER;
    private static String PASS;
    private static String DRIVER;
    static {
        InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("mysql.properties");
        Properties prop = new Properties();
        try {
            prop.load(is);
            URL = prop.getProperty("url");
            USER = prop.getProperty("user");
            PASS = prop.getProperty("password");
            DRIVER = prop.getProperty("driver");
            Class.forName(DRIVER);
        } catch (IOException e) {
            log.error("sth wrong with the property file loading pro", e);
        } catch (ClassNotFoundException e) {
            log.error("JDBCUtil:Class.forName(" + DRIVER + ") error", e);
        }
    }

    /**
     * 建立链接
     * 
     * @return
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(URL, USER, PASS);
        } catch (SQLException e) {
            log.error("JDBCUtil:getConnection() error", e);
        }
        return conn;
    }

    /**
     * 关闭资源
     * 
     * @param conn
     * @param st
     * @param rs
     */
    public static void closeMysqlResouces(Connection conn, Statement st, ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (Exception e) {
            log.error("JDBCUtil:rs.close() error", e);
        } finally {
            try {
                if (st != null) {
                    st.close();
                }
            } catch (Exception e2) {
                log.error("JDBCUtil:st.close() error", e2);
            } finally {
                try {
                    if (conn != null) {
                        conn.close();
                    }
                } catch (Exception e3) {
                    log.error("JDBCUtil:conn.close() error", e3);
                }
            }
        }
    }

}

主要是static代码块里处理资源加载与驱动,另外是提供链接和关闭资源的方法。日志使用了Apache的commons-logging。

首先测试一下链接的建立:

public class TestJDBCUtil {
    @Test
    public void testGetConn() {
        Object obj = JDBCUtil.getConnection();
        Assert.assertNotNull(obj);
    }

}

测试CRUD与事务的过程中,会对数据库增删改,要保证这些方法成功执行并不对原先的数据造成影响就要定义不同测试方法的执行顺序,这里采用了@FixMethodOrder(MethodSorters.NAME_ASCENDING)(4.11之后)按照方法名的字母顺序进行升序执行,保证所有方法成功执行后,数据库的数据不会改动:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;

import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

/**
 * @author Changjiang.Chen
 */
/**
 * 重新组合所有测试的执行顺序,按照字母表排序进行执行
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestCRUD {
    private Connection conn;
    private Statement st;
    private ResultSet rs;
    private PreparedStatement pst;

    @Test
    public void testAInsert() {
        try {
            conn = JDBCUtil.getConnection();
            st = conn.createStatement();
            String sql = "INSERT INTO content(id,type,info,num,validtime,label) VALUES(7,‘测试‘,‘测试信息‘,0,10,‘chiq3_test‘)";
            int r = st.executeUpdate(sql);
            JDBCUtil.closeMysqlResouces(conn, st, null);
            Assert.assertEquals(1, r);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.closeMysqlResouces(conn, st, null);
        }
    }

    /**
     * 参数传入方式可能引起SQL注入
     * 
     * @throws SQLException
     */
    @Test
    public void testCQuery1() throws SQLException {
        try {
            conn = JDBCUtil.getConnection();
            st = conn.createStatement();
            /**
             * param may be affected
             */
            String injectParam = "1";
            String sql = "select type from content where id = " + injectParam;
            rs = st.executeQuery(sql);
            String type = "";
            if (rs.next()) {
                type = rs.getString("type");
            }
            Assert.assertEquals("追剧推送", type);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.closeMysqlResouces(conn, st, rs);
        }
    }

    /**
     * preparedStatement对比Statement<br>
     * 如果可以保证sql语句不包含调用者传入的参数,可用后者,否则用前者<br>
     * 大部分情况下都倾向于使用前者,DBUtil,Hibernate都采用了pst
     * 
     * @throws SQLException
     */
    @Test
    public void testCQuery2() throws SQLException {
        try {
            conn = JDBCUtil.getConnection();
            /**
             * param could not be affected
             */
            String injectParam = "1";
            String sql = "select type from content where id = ?";
            pst = conn.prepareStatement(sql);
            pst.setString(1, injectParam);
            rs = pst.executeQuery();
            String type = "";
            if (rs.next()) {
                type = rs.getString("type");
            }
            Assert.assertEquals("追剧推送", type);
        } catch (Exception e) {
            e.printStackTrace(); // TODO: handle exception
        } finally {
            JDBCUtil.closeMysqlResouces(conn, pst, rs);
        }
    }

    /**
     * pst应用场景<br>
     * 1.放置sql注入 <br>
     * 2.大数据处理:用IO流处理参数 <br>
     * 3.批处理
     * 
     * @throws SQLException
     */
    @Test
    public void testCUpdate() throws SQLException {
        try {
            conn = JDBCUtil.getConnection();
            String injectParam = "7";
            String sql = "UPDATE content SET type = ‘TEST_PUSH‘ WHERE id = ?";
            pst = conn.prepareStatement(sql);
            pst.setString(1, injectParam);
            int r = pst.executeUpdate();
            Assert.assertEquals(1, r);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.closeMysqlResouces(conn, pst, rs);
        }
    }

    /**
     * 批量操作
     * 
     * @throws SQLException
     */
    @Test
    public void testYBatchUpdate() throws SQLException {
        try {

            conn = JDBCUtil.getConnection();
            String sql = "INSERT INTO content(id,type,info,num,validtime,label) VALUES(?,?,?,?,?,?)";
            pst = conn.prepareStatement(sql);
            for (int i = 10; i < 30; i++) {
                pst.setInt(1, i);
                pst.setString(2, "测试推送");
                pst.setString(3, "测试信息");
                pst.setInt(4, i);
                pst.setInt(5, 10);
                pst.setString(6, "开启测试推送模式");
                pst.addBatch();
            }
            int[] r = pst.executeBatch();
            int[] expected = new int[20];
            for (int i = 0; i < expected.length; i++) {
                expected[i] = 1;
            }
            Assert.assertEquals(Arrays.toString(expected), Arrays.toString(r));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.closeMysqlResouces(conn, pst, null);
        }
    }

    /**
     * Transaction
     */
    @Test
    public void testZTransaction() {
        conn = JDBCUtil.getConnection();
        try {
            conn.setAutoCommit(false);
            st = conn.createStatement();
            int r1 = st.executeUpdate("delete from content where id = 7");
            int r2 = st.executeUpdate("DELETE FROM content WHERE validtime = 10");
            conn.commit();
            Assert.assertEquals(Arrays.toString(new int[] { r1, r2 }), Arrays.toString(new int[] { 1, 20 }));
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            JDBCUtil.closeMysqlResouces(conn, st, null);
        }
    }

}

以上是关于基本的JDBC以及CRUD/Transaction基本操作的主要内容,如果未能解决你的问题,请参考以下文章

JDBC编程Java 连接 MySQL 基本过程以及封装数据库工具类

springboot自动配置源码解读以及jdbc和redis配置原理小点

Spring学习记录(十四)---JDBC基本操作

JDBC封装学习笔记---面向对象的JDBC

JDBC 基础

JDBC与Spring事务及事务传播性原理解析-上篇