Java JDBC核心技术,新手教学,步步深入

1、数据库连接的五种方式

#注意点:涉及到的驱动以及配置文件,有需要的请留言

package com.powernode.jdbc;

import org.junit.Test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class ConnectionTest {
    
    
    //方式一
    @Test
    public void test1() throws SQLException {
    
    
        //1、获取driver的实现类对象
        Driver driver = new com.mysql.jdbc.Driver();
        String url = "jdbc:mysql://106.14.36.65:3306/test";
        Properties info = new Properties();
        info.setProperty("user","root");
        info.setProperty("password","root");
        Connection con = driver.connect(url, info);
        System.out.println(con);
    }

    //方式二:对方式一的迭代
    //下面程序不出现第三方api,更具有移植性
    @Test
    public void test2() throws Exception {
    
    
        //1、获取driver的实现类对象,使用反射
        Class aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();

        //2、设置连接的数据库
        String url = "jdbc:mysql://106.14.36.65:3306/test";

        //3、设置连接的用户名密码
        Properties info = new Properties();
        info.setProperty("user","root");
        info.setProperty("password","root");

        //4、建立连接
        Connection connect = driver.connect(url, info);
        System.out.println(connect);
    }

    //方式三:使用DriverManager替换Driver
    @Test
    public void test3()throws Exception{
    
    
        //1、获取driver的实现类对象,使用反射
        Class aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();

        //2、提供连接的基本信息
        String url = "jdbc:mysql://106.14.36.65:3306/test";
        String user = "root";
        String password = "root";

        //3、注册驱动
        DriverManager.registerDriver(driver);

        //4、获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }

    //方式四:在三的基础上优化
    @Test
    public void test4()throws Exception{
    
    
        //1、提供连接的基本信息
        String url = "jdbc:mysql://106.14.36.65:3306/test";
        String user = "root";
        String password = "root";

        //2、加载driver
        Class.forName("com.mysql.jdbc.Driver");

        //4、获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }

    //方式五:将相关的数据库连接信息声明到配置文件中,通过读取配置文件的方式获取连接
    @Test
    public void test5()throws Exception{
    
    

        //1、读取配置文件连接数据库的基本信息
        //InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties prop = new Properties();
        prop.load(is);

        String url = prop.getProperty("url");
        String user = prop.getProperty("user");
        String password = prop.getProperty("password");

        //2、加载driver
        Class.forName(prop.getProperty("driver"));

        //3、获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }
}

2、增删改查

package com.powernode.preparestatement.curd;

import com.powernode.util.JDBCUtils;
import org.junit.Test;

import java.lang.reflect.Field;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

public class PrepareStatementCurd {
    
    
    //增删改查需要一个个执行才能看到实际效果
    public static void main(String[] args) throws ParseException {
    
    
        int row = 0;
        //添加
        String sql1 = "insert into customers(name,email,birth) values(?,?,?)";
        SimpleDateFormat simpDate = new SimpleDateFormat("yyyy-MM-dd");
        java.util.Date parse = simpDate.parse("1996-10-02");
        Date date = new Date(parse.getTime());
        row = JDBC(sql1, "Jack Chen", "[email protected]", date);

        //修改
        String sql2 = "update customers set name = ? where id = ?";
        row = JDBC(sql2,"Jack cxh",20);

        //删除
        String sql3 = "delete from customers where id = ?";
        row = JDBC(sql3,20);

        if(row > 0){
    
    
            System.out.println("成功");
        }else{
    
    
            System.out.println("失败");
        }

        //查询,当字段别名的时候,需要对应的属性名改变
        String sql4 = "select id,name,email,birth from customers where id = ?";
        System.out.println(selectAll(Customers.class,sql4,18));

        //查询多条
        String sql5 = "select id,name,email,birth from customers where id < ?";
        List<Customers> custList = get(Customers.class, sql5, 5);
        custList.forEach(System.out::println);
    }

    //封装JDBC(只使用增删改)
    public static int JDBC(String sql,Object ...args){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);

            //3、填充占位符(数据库索引从1开始)
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //4、执行sql,返回影响行数
            return pres.executeUpdate();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres);
        }

        return 0;
    }

    //添加一条记录
    @Test
    public void insert(){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            String sql = "insert into customers(name,email,birth) values(?,?,?)";
            pres = conn.prepareStatement(sql);

            //3、填充占位符(数据库索引从1开始)
            pres.setString(1,"Jack Chen");
            pres.setString(2,"[email protected]");
            SimpleDateFormat simpDate = new SimpleDateFormat("yyyy-MM-dd");
            java.util.Date parse = simpDate.parse("1996-10-02");
            pres.setDate(3,  new Date(parse.getTime()));

            //4、执行sql
            pres.execute();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres);
        }
    }

    //修改一条记录
    @Test
    public void update(){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            String sql = "update customers set name = ? where id = ?";
            pres = conn.prepareStatement(sql);

            //3、填充占位符(数据库索引从1开始)
            pres.setString(1,"Jack cxh");
            pres.setObject(2,19);

            //4、执行sql
            pres.execute();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres);
        }
    }

    //删除一条记录
    @Test
    public void delete(){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            String sql = "delete from customers where id = ?";
            pres = conn.prepareStatement(sql);

            //3、填充占位符(数据库索引从1开始)
            pres.setObject(1,19);

            //4、执行sql
            pres.execute();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres);
        }
    }

    //查询一条记录
    @Test
    public void select(){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        ResultSet result = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            String sql = "select id,name,email,birth from customers where id = ?";
            pres = conn.prepareStatement(sql);
            pres.setObject(1,18);

            //4、执行,返回结果集
            result = pres.executeQuery();
            if(result.next()){
    
    
                int id = result.getInt(1);
                String name = result.getString(2);
                String email = result.getString(3);
                Date date = result.getDate(4);
                Customers customers = new Customers(id,name,email,date);
                System.out.println(customers);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres,result);
        }
    }

    //封装查询,针对单个表的(单条)
    @Test
    public static Customers selects(String sql,Object ...args){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        ResultSet result = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //4、执行,返回结果集
            result = pres.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData metaData = result.getMetaData();
            //获取结果集的列数
            int columnCount = metaData.getColumnCount();
            if(result.next()){
    
    
                Customers customers = new Customers();
                for (int i = 0; i < columnCount; i++) {
    
    
                    //每列的value值
                    Object columnValue = result.getObject(i + 1);
                    //每列的属性名的别名
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    //通过反射,给属性赋值
                    Field field = Customers.class.getDeclaredField(columnLabel);
                    field.setAccessible(true);  //私有属性需要开放权限
                    field.set(customers,columnValue);
                }

                return customers;
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres,result);
        }

        return null;
    }

    //封装查询,所有表的(单条)
    @Test
    public static <T>T selectAll(Class<T> clazz,String sql,Object ...args){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        ResultSet result = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //4、执行,返回结果集
            result = pres.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData metaData = result.getMetaData();
            //获取结果集的列数
            int columnCount = metaData.getColumnCount();
            if(result.next()){
    
    
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
    
    
                    //每列的value值
                    Object columnValue = result.getObject(i + 1);
                    //每列的属性名的别名
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    //通过反射,给属性赋值
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);  //私有属性需要开放权限
                    field.set(t,columnValue);
                }

                return t;
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres,result);
        }

        return null;
    }

    //封装查询,所有表的(多条)
    @Test
    public static <T> List<T> get(Class<T> clazz,String sql,Object ...args){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        ResultSet result = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //4、执行,返回结果集
            result = pres.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData metaData = result.getMetaData();
            //获取结果集的列数
            int columnCount = metaData.getColumnCount();
            //创建集合对象
            List<T> list = new ArrayList<>();
            while (result.next()){
    
    
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
    
    
                    //每列的value值
                    Object columnValue = result.getObject(i + 1);
                    //每列的属性名的别名
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    //通过反射,给属性赋值
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);  //私有属性需要开放权限
                    field.set(t,columnValue);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres,result);
        }

        return null;
    }
}




package com.powernode.util;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @author cxhblog Email:[email protected]
 * @create 2021-01-28 11:51
 * @verson 1.0.0
 */
public class JDBCUtils {
    
    
    /**
     * @author cxhblog Email:[email protected]
     * @create  15:53
     * @return java.sql.Connection
     */
    public static Connection getConnection() throws Exception {
    
    
        //1、读取配置文件连接数据库的基本信息
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties prop = new Properties();
        prop.load(is);

        String url = prop.getProperty("url");
        String user = prop.getProperty("user");
        String password = prop.getProperty("password");

        //2、加载driver
        Class.forName(prop.getProperty("driver"));

        //3、获取连接
        Connection connection = DriverManager.getConnection(url, user, password);

        return connection;
    }

    /**
     * 关闭资源连接
     * @author cxhblog Email:[email protected]
     * @create  16:00
     * @return void
     */
    public static void closeResource(Connection conn, Statement pres){
    
    
        //关闭资源
        if (pres != null){
    
    
            try {
    
    
                pres.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }

        if(conn != null){
    
    
            try {
    
    
                conn.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 关闭资源连接
     * @author cxhblog Email:[email protected]
     * @create  15:45
     * @params [conn, pres, result]
     * @return void
     */
    public static void closeResource(Connection conn, Statement pres, ResultSet result){
    
    
        //关闭资源
        if (pres != null){
    
    
            try {
    
    
                pres.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }

        if(conn != null){
    
    
            try {
    
    
                conn.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }

        if(result != null){
    
    
            try {
    
    
                result.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
    }
}

package com.powernode.preparestatement.curd;

import java.sql.Date;

/**
 * @author cxhblog Email:[email protected]
 * @create 2021-01-29 15:38
 * @verson 1.0.0
 */
public class Customers {
    
    
    private int id;
    private String name;
    private String email;
    private Date birth;

    public Customers() {
    
    
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getEmail() {
    
    
        return email;
    }

    public void setEmail(String email) {
    
    
        this.email = email;
    }

    public Date getBirth() {
    
    
        return birth;
    }

    public void setBirth(Date birth) {
    
    
        this.birth = birth;
    }

    public Customers(int id, String name, String email, Date birth) {
    
    
        this.id = id;
        this.name = name;
        this.email = email;
        this.birth = birth;
    }

    @Override
    public String toString() {
    
    
        return "Customers{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", birth=" + birth +
                '}';
    }
}

3、对blob类型数据的操作

package com.powernode.blob;

import com.powernode.preparestatement.curd.Customers;
import com.powernode.util.JDBCUtils;
import org.junit.Test;

import java.io.*;
import java.sql.*;

/**
 * @author cxhblog Email:[email protected]
 * @create 2021-02-01 15:05
 * @verson 1.0.0
 */
public class BlobTest {
    
    
    //插入
    public static void main(String[] args){
    
    
        Connection connection = null;
        PreparedStatement prep = null;
        FileInputStream fis = null;
        try {
    
    
            //连接数据库
            connection = JDBCUtils.getConnection();

            //预编译sql
            String sql = "insert into customers(name,email,birth,photo) values(?,?,?,?)";
            prep = connection.prepareStatement(sql);

            //设置插入数据
            prep.setObject(1,"YangMi");
            prep.setObject(2,"[email protected]");
            prep.setObject(3,"1986-02-26");
            fis = new FileInputStream(new File("ym.jpg"));
            prep.setObject(4,fis);

            //执行sql
            prep.execute();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //关闭资源
            if(fis != null){
    
    
                try {
    
    
                    fis.close();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }
            }
            JDBCUtils.closeResource(connection,prep);
        }

    }

    //查询
    @Test
    public void test(){
    
    
        Connection connection = null;
        PreparedStatement prep = null;
        ResultSet res = null;
        InputStream binaryStream = null;
        FileOutputStream fos = null;
        try {
    
    
            //连接数据库
            connection = JDBCUtils.getConnection();

            //预编译sql
            String sql = "select id,name,email,birth,photo from customers where id = ?";
            prep = connection.prepareStatement(sql);
            prep.setInt(1,26);

            //执行sql
            res = prep.executeQuery();
            if (res.next()) {
    
    
                //获取每个字段列的数据,赋值对象属性
                int id = res.getInt("id");
                String name = res.getString("name");
                String email = res.getString("email");
                Date birth = res.getDate("birth");
                Customers cust = new Customers(id,name,email,birth);
                System.out.println(cust);

                //下载blob类型数据,以文件的格式保存到本地
                Blob photo = res.getBlob("photo");
                binaryStream = photo.getBinaryStream();
                fos = new FileOutputStream("ym.jpg");
                byte[] buffer = new byte[1024];
                int len;
                while ((len = binaryStream.read(buffer)) != -1) {
    
    
                    fos.write(buffer,0,len);
                }
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //关闭资源
            if(binaryStream != null){
    
    
                try {
    
    
                    binaryStream.close();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }
            }
            if(fos != null){
    
    
                try {
    
    
                    fos.close();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }
            }
            JDBCUtils.closeResource(connection,prep,res);
        }
    }

    //批量插入(循环)
    @Test
    public void test1(){
    
    
        Connection connection = null;
        PreparedStatement prep = null;
        try {
    
    
            //连接数据库
            connection = JDBCUtils.getConnection();

            //预编译sql
            String sql = "insert into goods(name) values(?)";
            prep = connection.prepareStatement(sql);

            long start = System.currentTimeMillis() / 1000;

            //循环插入
            for (int i = 0; i < 5000; i++) {
    
    
                prep.setString(1,"name_" + i);
                prep.execute();
            }

            long end = System.currentTimeMillis() / 1000;

            System.out.println("插入花费时间:" + (end - start));

        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(connection,prep);
        }
    }

    //批量插入(高效方式:addBatch,executeBatch,clearBatch)
    //注意:mysql默认关闭批量处理,需要设置参数开启mysql的支持,并且更新mysql驱动
    //参数:?rewriteBatchedStatements=true 写在配置文件url后面,也就是(jdbc:mysql://106.14.36.65:3306/test)后
    //驱动:mysql-connector-java-5.1.37-bin.jar
    //设置连接不允许自动提交数据
    @Test
    public void test2(){
    
    
        Connection connection = null;
        PreparedStatement prep = null;
        try {
    
    
            //连接数据库
            connection = JDBCUtils.getConnection();

            //设置不允许自动提交数据
            connection.setAutoCommit(false);

            //预编译sql
            String sql = "insert into goods(name) values(?)";
            prep = connection.prepareStatement(sql);

            long start = System.currentTimeMillis() / 1000;

            //循环插入
            for (int i = 0; i < 5000; i++) {
    
    
                prep.setString(1,"name_" + i);
                //赞存sql
                prep.addBatch();
                if(i % 100 == 0){
    
    
                    prep.executeBatch();
                    prep.clearBatch();
                }
            }

            //统一提交数据
            connection.commit();

            long end = System.currentTimeMillis() / 1000;

            System.out.println("插入花费时间:" + (end - start));

        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(connection,prep);
        }
    }
}

4、数据库事务

#事务的ACID属性
#1、原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么不发生
#2、一致性:事务必须使数据库从一个一致性状态换到另外一个一致性状态
#3、隔离性:指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务
		  #是隔离的,并发执行的各个事务之间不能相互干扰
#4、持久性:指一个事务一旦被提交,它对数据库中的数据的改变就是永久性的,接下来的其他操作和数据库
		  #故障不应该对其有影响
package com.powernode.transation;

import com.powernode.util.JDBCUtils;
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author cxhblog Email:[email protected]
 * @create 2021-02-02 14:29
 * @verson 1.0.0
 */
public class TransationTest {
    
    
    //普通修改
    public static void main(String[] args) {
    
    
        String sql1 = "update user_table set balance=900 where user=?";
        JDBC(sql1,"AA");

        //模拟异常
        System.out.println(10 / 0);

        String sql2 = "update user_table set balance=1100 where user=?";
        JDBC(sql2,"BB");

        System.out.println("转账成功");
    }

    //事务操作
    @Test
    public void test(){
    
    
        Connection conn = null;
        try {
    
    
            //连接数据库
            conn = JDBCUtils.getConnection();

            //取消自动提交数据
            conn.setAutoCommit(false);

            String sql1 = "update user_table set balance=900 where user=?";
            JDBC(conn,sql1,"AA");

            //模拟异常
            System.out.println(10 / 0);

            String sql2 = "update user_table set balance=1100 where user=?";
            JDBC(conn,sql2,"BB");

            //提交数据
            conn.commit();
        } catch (Exception e) {
    
    
            e.printStackTrace();
            //回滚数据
            try {
    
    
                conn.rollback();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        } finally {
    
    
            JDBCUtils.closeResource(conn,null);
        }

        System.out.println("转账成功");
    }

    //封装JDBC(只使用增删改)
    public static int JDBC(String sql,Object ...args){
    
    
        Connection conn = null;
        PreparedStatement pres = null;
        try {
    
    
            //1、连接数据库
            conn = JDBCUtils.getConnection();

            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);

            //3、填充占位符(数据库索引从1开始)
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //4、执行sql,返回影响行数
            return pres.executeUpdate();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(conn,pres);
        }

        return 0;
    }

    //封装JDBC(事务)
    public static int JDBC(Connection conn,String sql,Object ...args){
    
    
        PreparedStatement pres = null;
        try {
    
    
            //1、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);

            //2、填充占位符(数据库索引从1开始)
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //3、执行sql,返回影响行数
            return pres.executeUpdate();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //恢复为自动提交
            try {
    
    
                conn.setAutoCommit(true);
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
            //4、关闭资源
            JDBCUtils.closeResource(null,pres);
        }

        return 0;
    }
}

4、数据库并发问题

#对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,
#就会导致各种并发问题:

#脏读:对于两个事务T1, T2, T1读取了已经被T2更新但还没有被提交的字段。
	 #之后,若T2回滚, T1读取的内容就是临时且无效的。

#不可重复读:对于两个事务T1, T2, T1读取了一个字段,然后T2更新了该字段。
		   #之后, T1再次读取同一个字段,值就不同了。
		   
#幻读:对于两个事务T1,T2,T1从一个表中读取了-个字段,然后T2在该表中插入了一些新的行。
	  #之后,如果T1再次读取同一一个表就会多出几行。

#数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。

#一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,
# **隔离级别越高,数据一致性就越好, 但并发性越弱。**

#四种隔离级别:
#1、READ UNCOMMITTED(读未提交数据):
#描述:允许事务读取未被其他事物提交的变更脏读,不可重复读和幻读的问题都会出现

#2、READ COMMITED(读已提交数据):
#只允许事务读取已经被其它事务提交的变更,可以避免脏读,但不可重复读和幻读问题仍然可能出现

#3、REPEATABLE READ(可重复读):
#确保事务可以多次从一个字段中读取相同的值在这个事务持续期间,禁止其他事物
#对这个字段进行更新可以避免脏读和不可重复读,但幻读的问题仍然存在

#4、SERIALIZABLE(串行化):
#确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入。
#更新和删除操作.所有并发问题都可以避免,但性能十分低下.

#Oracle支持2种事务隔离级别:1,4,默认1
#Mysql支持四种事务隔离级别:默认4
package com.powernode.transation;

import com.powernode.util.JDBCUtils;
import org.junit.Test;

import java.lang.reflect.Field;
import java.sql.*;

/**
 * @author cxhblog Email:[email protected]
 * @create 2021-02-03 16:42
 * @verson 1.0.0
 */
public class TransationTest1 {
    
    
    @Test
    public void select() throws Exception {
    
    
        Connection conn = JDBCUtils.getConnection();
        //设置隔离级别:读未提交数据(脏读)
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        //设置隔离级别:读已提交数据
//        conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
        //隔离级别
        System.out.println(conn.getTransactionIsolation());
        //取消自动提交
        conn.setAutoCommit(false);

        String sql = "select user,password,balance from user_table where user = ?";
        User user = selectAll(conn, User.class, sql, "CC");
        System.out.println(user);
    }

    @Test
    public void update() throws Exception {
    
    
        Connection conn = JDBCUtils.getConnection();
        //取消自动提交
        conn.setAutoCommit(false);

        String sql = "update user_table set balance = ? where user = ?";
        TransationTest1.JDBC(conn, sql, 5000,"CC");
        Thread.sleep(10000);

        System.out.println("修改结束");
    }

    //封装JDBC(事务)
    public static int JDBC(Connection conn,String sql,Object ...args){
    
    
        PreparedStatement pres = null;
        try {
    
    
            //1、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);

            //2、填充占位符(数据库索引从1开始)
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //3、执行sql,返回影响行数
            return pres.executeUpdate();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    

            //4、关闭资源
            JDBCUtils.closeResource(null,pres);
        }

        return 0;
    }

    //封装查询,所有表的(单条事务版)
    public static <T>T selectAll(Connection conn,Class<T> clazz,String sql,Object ...args){
    
    
        PreparedStatement pres = null;
        ResultSet result = null;
        try {
    
    
            //2、预编译sql语句,返回preparedStatement的实例 ?为占位符
            pres = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
    
    
                pres.setObject(i + 1,args[i]);
            }

            //4、执行,返回结果集
            result = pres.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData metaData = result.getMetaData();
            //获取结果集的列数
            int columnCount = metaData.getColumnCount();
            if(result.next()){
    
    
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
    
    
                    //每列的value值
                    Object columnValue = result.getObject(i + 1);
                    //每列的属性名的别名
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    //通过反射,给属性赋值
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);  //私有属性需要开放权限
                    field.set(t,columnValue);
                }

                return t;
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //5、关闭资源
            JDBCUtils.closeResource(null,pres,result);
        }

        return null;
    }
}

5、在Mysql中设置隔离级别

#查看当前的隔离级别
SELECT @@tx_isolation;
#设置当前 mySQL 连接的隔离级别
set transaction isolation level read committed;
#设置数据库系统的全局的隔离级别
set global transaction isolation level read committed;

#下面是测试创建的用户,可忽略
#创建mysql数据库用户
create user tom identified by 'abc123';
#授予通过网络方式登录的tom用户,对所有库所有表的全部权限,密码设为abc123. 
grant all privileges on *.* to tom@'%' identified by 'abc123';
#给tom用户使用本地命令行方式,授予atguigudb这个库下的所有表的插删改查的权限。 
grant select,insert,delete,update on atguigudb.* to tom@localhost identified by 'abc123';

6、数据库连接池
(1)c3p0数据库连接池

package com.powernode.connection;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;
import org.junit.Test;

import java.sql.Connection;

/**
 * @author cxhblog Email:[email protected]
 * @Description 描述
 * @create 2021-02-22 14:48
 * @verson 1.0.0
 */
public class C3P0Test {
    
    
    @Test
    public void test1() throws Exception {
    
    
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        cpds.setDriverClass( "com.mysql.jdbc.Driver" ); //loads the jdbc driver
        cpds.setJdbcUrl( "jdbc:mysql://106.14.36.65:3306/test" );
        cpds.setUser("root");
        cpds.setPassword("root");
        //设置初始连接池连接数
        cpds.setInitialPoolSize(10);
        Connection conn = cpds.getConnection();
        System.out.println(conn);
        //销毁连接池
//        DataSources.destroy(cpds);
    }

    //使用xml配置文件
    static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
    @Test
    public void test2() throws Exception {
    
    
        Connection conn = cpds.getConnection();
        System.out.println(conn);
    }
}


#c3p0-config.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
    <named-config name="helloc3p0">
        <!-- 获取提供连接的四个基本信息 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://106.14.36.65:3306/test</property>
        <property name="user">root</property>
        <property name="password">root</property>

        <!-- 进行数据库连接池基本管理的基本信息 -->

        <!-- 当数据库连接池连接数不过时,一次性申请的连接数 -->
        <property name="acquireIncrement">50</property>
        <!-- 数据库连接池初始化的连接数 -->
        <property name="initialPoolSize">100</property>
        <!-- 数据库连接池维护的最小连接数 -->
        <property name="minPoolSize">50</property>
        <!-- 数据库连接池维护的最大连接数 -->
        <property name="maxPoolSize">1000</property>
        <!-- 数据库连接池最多维护的statement数 -->
        <property name="maxStatements">50</property>
        <!-- 每个连接最多使用的statement数 -->
        <property name="maxStatementsPerConnection">5</property>
    </named-config>
</c3p0-config>

(2)dbcp数据库连接池

package com.powernode.connection;

import com.sun.deploy.util.Property;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;

import javax.sql.DataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * @author cxhblog Email:[email protected]
 * @Description 描述
 * @create 2021-02-22 15:41
 * @verson 1.0.0
 */
public class DBCPTest {
    
    
    /**
     * dbcp连接池常用基本配置属性
     *
     * 1.initialSize :连接池启动时创建的初始化连接数量(默认值为0)
     *
     * 2.maxActive :连接池中可同时连接的最大的连接数(默认值为8,调整为20,高峰单机器在20并发左右,自己根据应用场景定)
     *
     * 3.maxIdle:连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限制(默认为8个,maxIdle不能设置太小,因为假如在高负载的情况下,连接的打开时间比关闭的时间快,会引起连接池中idle的个数 上升超过maxIdle,而造成频繁的连接销毁和创建,类似于jvm参数中的Xmx设置)
     *
     * 4.minIdle:连接池中最小的空闲的连接数,低于这个数量会被创建新的连接(默认为0,调整为5,该参数越接近maxIdle,性能越好,因为连接的创建和销毁,都是需要消耗资源的;但是不能太大,因为在机器很空闲的时候,也会创建低于minidle个数的连接,类似于jvm参数中的Xmn设置)
     *
     * 5.maxWait  :最大等待时间,当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常,如果设置-1表示无限等待(默认为无限,调整为60000ms,避免因线程池不够用,而导致请求被无限制挂起)
     *
     * 6.poolPreparedStatements:开启池的prepared(默认是false,未调整,经过测试,开启后的性能没有关闭的好。)
     *
     * 7.maxOpenPreparedStatements:开启池的prepared 后的同时最大连接数(默认无限制,同上,未配置)
     *
     * 8.minEvictableIdleTimeMillis  :连接池中连接,在时间段内一直空闲, 被逐出连接池的时间
     *
     * 9.removeAbandonedTimeout  :超过时间限制,回收没有用(废弃)的连接(默认为 300秒,调整为180)
     *
     * 10.removeAbandoned  :超过removeAbandonedTimeout时间后,是否进 行没用连接(废弃)的回收(默认为false,调整为true)
     */

    @Test
    public void test1() throws Exception {
    
    
        BasicDataSource basic = new BasicDataSource();
        basic.setDriverClassName("com.mysql.jdbc.Driver");
        basic.setUrl("jdbc:mysql://106.14.36.65:3306/test");
        basic.setUsername("root");
        basic.setPassword("root");
        Connection conn = basic.getConnection();
        System.out.println(conn);
    }

    //使用配置文件
    private static DataSource source;
    static{
    
    
        try {
    
    
            Properties prop = new Properties();
            //方式一
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
            //方式二
//        FileInputStream is = new FileInputStream(new File("src/dbcp.properties"));
            prop.load(is);
            source = BasicDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    @Test
    public void test2() throws Exception {
    
    
        Connection conn = source.getConnection();
        System.out.println(conn);
    }
}

#dbcp.properties配置文件
url=jdbc:mysql://106.14.36.65:3306/test
username=root
password=root
driverClassName=com.mysql.jdbc.Driver

(3)Druid(德鲁伊)数据库连接池(推荐使用)

package com.powernode.connection;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.Test;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * @author cxhblog Email:[email protected]
 * @Description 描述
 * @create 2021-02-23 9:58
 * @verson 1.0.0
 */
public class DruidTest {
    
    
    private static DataSource source;
    static {
    
    
        try {
    
    
            Properties prop = new Properties();
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
            prop.load(is);
            source = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    @Test
    public void test1() throws Exception {
    
    
        Connection conn = source.getConnection();
        System.out.println(conn);
    }
}

#druid.properties配置文件
url=jdbc:mysql://106.14.36.65:3306/test
username=root
password=root
driverClassName=com.mysql.jdbc.Driver

7、Apache-DBUtils实现CRUD操作

#封装了针对数据库的增删改查操作
package com.powernode.dbutils;

import com.powernode.preparestatement.curd.Customers;
import com.powernode.util.JDBCUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import org.junit.Test;

import java.sql.Connection;
import java.util.List;
import java.util.Map;

/**
 * @author cxhblog Email:[email protected]
 * @Description 描述
 * @create 2021-02-23 10:21
 * @verson 1.0.0
 */
public class QueryRunnerTest {
    
    
    @Test
    public void insert(){
    
    
        Connection conn = null;
        try {
    
    
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getDruidConnection();
            String sql = "insert into customers(name,email,birth) values(?,?,?)";
            int row = runner.update(conn, sql, "Jack Chen", "[email protected]", "1996-10-02");
            System.out.println(row);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(conn,null);
        }
    }

    //查询单条
    @Test
    public void query(){
    
    
        Connection conn = null;
        try {
    
    
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getDruidConnection();
            String sql = "select id,name,email,birth from customers where id = ?";
            BeanHandler<Customers> handler = new BeanHandler<>(Customers.class);
            Customers customers = runner.query(conn, sql, handler, 27);
            System.out.println(customers);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(conn,null);
        }
    }

    //查询多条
    @Test
    public void queryList(){
    
    
        Connection conn = null;
        try {
    
    
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getDruidConnection();
            String sql = "select id,name,email,birth from customers where id > ?";
            BeanListHandler<Customers> handler = new BeanListHandler<>(Customers.class);
            List<Customers> list = runner.query(conn, sql, handler, 25);
            list.forEach(System.out::println);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(conn,null);
        }
    }

    //查询单条(Map)
    @Test
    public void queryMap(){
    
    
        Connection conn = null;
        try {
    
    
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getDruidConnection();
            String sql = "select id,name,email,birth from customers where id > ?";
            MapHandler handler = new MapHandler();
            Map<String, Object> map = runner.query(conn, sql, handler, 25);
            System.out.println(map);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(conn,null);
        }
    }

    //查询多条条(MapList)
    @Test
    public void queryMapList(){
    
    
        Connection conn = null;
        try {
    
    
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getDruidConnection();
            String sql = "select id,name,email,birth from customers where id > ?";
            MapListHandler handler = new MapListHandler();
            List<Map<String, Object>> mapList = runner.query(conn, sql, handler, 25);
            mapList.forEach(System.out::println);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(conn,null);
        }
    }

    @Test
    public void count() {
    
    
        Connection conn = null;
        try {
    
    
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getDruidConnection();
            String sql = "select count(*) from customers";
            ScalarHandler handler = new ScalarHandler();
            Long count = (Long) runner.query(conn, sql, handler);
            System.out.println(count);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            JDBCUtils.closeResource(conn,null);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/cxhblog/article/details/113309316