Jdbc入门
- Jdbc本质(一套接口)
- 数据库事物的引入
Jdbc本质(一套接口)
1.jdbc 是什么?
Java DataBase Connectivity(Java语言连接数据库)
2.jdbc的本质是什么?
思考:为什么sun公司要制定一套jdbc接口呢?
 因为每一个数据库的实现原理都不一样。
 Oracle有自己的实现原理。
 MySql也有自己的实现原理。
 MysqlServer也有自己的实现原理。
 。。
 每一个数据库都有自己独特的实现原理
 
3. JDBC体系结构
JDBC接口(API)包括两个层次︰
 1.面向应用的API : JavaAPI,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
2.面向数据库的API: Java Driver API,供开发商开发数据库驱动程序用。
JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。
 不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。
4.JDBC编程六步(需要背会)
第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)
 第二步:获取连接(表示Java的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要)第三步:获取数据库操作对象(专门执行sql语句的对象)
 第四步:执行sql语句(DQLDML…)
 第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
 第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)
5.获取数据库连接的方法
方法一:
 @Test
    public void testConnection1() throws SQLException{
        Driver driver=new com.mysql.cj.jdbc.Driver();
        //url:http://localhost:8080/gmall/keyboard.jpg
        //jdbc:mysql协议
        //localhost:ip地址
        //3306:默认mysql的端口号
        //mybatis:mybatis的数据库
      //注册驱动:告诉Java程序,即将要连接的是哪个品牌的数据库
        String url="jdbc:mysql://localhost:3306/mybatis";
        //获取连接:表示java进程和数据库进程之间的通道打开了,这属于进程之间的通信
        //将用户名和密码封装在Properties中
        Properties info = new Properties();
        info.setProperty("user","root");
        info.setProperty("password","");
        Connection conn=driver.connect(url,info);
        System.out.println(conn);
    }
方法二:
//方式二:对方式一的迭代
    @Test
    public void testConnection2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
       //获取Driver实现类对象,使用反射
        Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
        Driver driver=(Driver)aClass.newInstance();
        String url="jdbc:mysql://localhost:3306/mybatis";
        Properties info = new Properties();
        info.setProperty("user","root");
        info.setProperty("password","");
        Connection conn=driver.connect(url,info);
        System.out.println(conn);
    }
 //方式三:使用DriverManage替换Driver
    @Test
    public void testConnection() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
        //1.获取Driver的实现类对象
        Class<?>  clazz = Class.forName("com.mysql.cj.jdbc.Driver");
        Driver driver=(Driver)clazz.newInstance();
        //2.提供另外三个连接的基本信息
        String url="jdbc:mysql://localhost:3306/mybatis";
        String user="root";
        String password="";
        //注册驱动
        DriverManager.registerDriver(driver);
        //获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }
//方法四:可以只是加载驱动,不用显示的注册驱动
    @Test
    public void testConnection4() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
        //2.提供另外三个连接的基本信息
        String url="jdbc:mysql://localhost:3306/mybatis";
        String user="root";
        String password="";
        //1.获取Driver的实现类对象
        Class.forName("com.mysql.cj.jdbc.Driver");
//        Driver driver=(Driver)clazz.newInstance();
        //注册驱动
//        DriverManager.registerDriver(driver);
        //为什么可以省略上述操作呢?
        /*
        * 在mysql的Driver实现类中,声明了如下操作
        *  static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
      }
        *
        *
        * */
        //获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }
JAVA 笔记 ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别?
 复习反射的三种 类加载器
 https://www.cnblogs.com/yjl49/archive/2012/08/08/2628502.html
 Properties类总结https://blog.csdn.net/yelang0/article/details/76449165
方式五:(复习)
/方式五:将数据库连接需要的四个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接
    @Test
    public void testConnection5() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException, IOException {
       //1.读取配置文件的四个基本信息
        InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties pros = new Properties();
        pros.load(is);
        String user=pros.getProperty("user");
        String password=pros.getProperty("password");
        String url=pros.getProperty("url");
        String driver=pros.getProperty("driver");
        //2.加载驱动
        Class.forName(driver);
        //3.获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
        
    }
如果出现空指针异常,有可能是properties的存放位置不对。
 
ser=root
password=
url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8
driver=com.mysql.cj.jdbc.Driver
导入driver驱动
 
 注意:每新建一个moudle建立数据库连接的时候都要执行这三步
5.1精简版(复习)
1.获取数据库连接核心代码两步:
1.注册驱动 注意Class.forName().newInstance()的使用
  //注册驱动
        DriverManager.registerDriver(driver);
2.获取连接
//获取连接
        Connection connection = DriverManager.getConnection(url, user, pwd);
        if(connection!=null){
            System.out.println("连接成功");
        }
3.运行
import org.junit.Test;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
 * @description:使用DriverManager获取数据库连接
 * @author: Ada
 * @time: 2022/3/14
 */
public class MyConnectionTest {
    @Test
    public void test() throws Exception {
        //com.mysql.cj.jdbc.Driver driver = new com.mysql.cj.jdbc.Driver();
        Driver driver = (Driver)Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
        //注册驱动
        DriverManager.registerDriver(driver);
        String url="jdbc:mysql://localhost:3306/mybatis";
        String user="root";
        String pwd="";
        //获取连接
        Connection connection = DriverManager.getConnection(url, user, pwd);
        if(connection!=null){
            System.out.println("连接成功");
        }
    }
}
6.使用Statement的弊端
需要拼写sql语句,并且存在SQL注入的问题
 三个判断,最后while 1=1是true.
 //如歌避免sql注入,使用PrepareStatement(从Statement扩展而来)取代Statement
 
7.使用PrepareStatement实现增删改查
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channel;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/*
*
* 使用PreparedStatement来替换Statement,实现对数据表的增删改查操作
*
* */
public class PreparedStatementUpdateTest {
    @Test
    public void testConnection5() throws Exception {
        PreparedStatement ps= null;
        Connection conn=null;
        try {
            //1.读取配置文件的四个基本信息
            InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
            Properties pros = new Properties();
            pros.load(is);
            String user=pros.getProperty("user");
            String password=pros.getProperty("password");
            String url=pros.getProperty("url");
            String driver=pros.getProperty("driver");
            //2.加载驱动
            Class.forName(driver);
            //3.获取连接
             conn = DriverManager.getConnection(url, user, password);
            //4.预编译sql语句,返回PreparedStatement实例
            String sql="insert into user(id,name,pwd)values(?,?,?)";
            ps = conn.prepareStatement(sql);
            //5.填充占位符
            ps.setInt(1,4);
            ps.setString(2,"王红");
            ps.setString(3,"345678");
            //6.执行sql
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            //7.资源的关闭
            try {
                if(ps!=null)
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if(conn!=null)
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

 补充知识点:idea设置类注释和方法注释
 https://blog.csdn.net/weixin_39911998/article/details/114114030?
 易错点:
 1.如果出现乱码,在properties属性文件中的url后面添加
 ?characterEncoding=UTF-8设置一下字符集
 实现通用的增删改查操作
 为什么有些String需要加双引号而有些不需要
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channel;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/*
*
* 使用PreparedStatement来替换Statement,实现对数据表的增删改查操作
*
* */
public class PreparedStatementUpdateTest {
    //修改customers表的一条记录
    @Test
    public void testUpdate() {
        PreparedStatement ps= null;
        Connection conn=null;
        //1.获取数据库的连接
        try {
            conn = JDBCutils.getConnection();
            //2.预编译sql语句,返回PreparedStatement的实例
             String sql ="update user set name = ? where id = ? ";
             ps = conn.prepareStatement(sql);
            //3.填充占位符
            ps.setString(1,"莫扎特");
            ps.setInt(2,2);
            //4.执行
            ps.execute();
            //5.资源的关闭
            JDBCutils.closeResource(ps,conn);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(conn!=null)
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if(ps!=null)
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void testConnection5() throws Exception {
        PreparedStatement ps= null;
        Connection conn=null;
        try {
            //1.读取配置文件的四个基本信息
            InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
            Properties pros = new Properties();
            pros.load(is);
            String user=pros.getProperty("user");
            String password=pros.getProperty("password");
            String url=pros.getProperty("url");
            String driver=pros.getProperty("driver");
            //2.加载驱动
            Class.forName(driver);
            //3.获取连接
             conn = DriverManager.getConnection(url, user, password);
            //4.预编译sql语句,返回PreparedStatement实例
            String sql="insert into user(id,name,pwd)values(?,?,?)";
            ps = conn.prepareStatement(sql);
            //5.填充占位符
            ps.setInt(1,4);
            ps.setString(2,"王红");
            ps.setString(3,"345678");
            //6.执行sql
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            //7.资源的关闭
            try {
                if(ps!=null)
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if(conn!=null)
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
实现通用的增删改查
public class PreparedStatementUpdateTest  {
    @Test
    public void testCommonUpdate(){
        String sql="delete from user where id=?";
        update(sql,4);
    }
    //通用的增删改查操作
    public void update(String sql,Object ...args){
        Connection conn=null;
        PreparedStatement ps=null;
        //1.获取数据库连接
        try {
           conn = JDBCutils.getConnection();
            //2.预编译sql语句,返回PreparedStatement的实例
           ps = conn.prepareStatement(sql);
            //3.填充占位符
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            //4.执行
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCutils.closeResource(ps,conn);
        }
    }
Java与SQL对应数据类型转换表
 
7.1查
import com.sun.org.apache.regexp.internal.RE;
import javafx.beans.binding.ObjectBinding;
import org.junit.Test;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/**
 * @description:z针对user表的查询操作
 * @author: Ada
 * @time: 2022/3/13
 */
public class userQuery {
    /*
    *
    * **
     * @description:针对user表的通用查询操作
     * @author: Ada
     * @time: 2022/3/13
     */
    @Test
    public void testQueryForCustomers() throws Exception {
        String sql="select id,name,pwd from user where id=?";
        Customer customer=queryForCustomers(sql,3);
        System.out.println(customer);
    }
    public  Customer queryForCustomers(String sql, Object...args) throws Exception {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn = JDBCutils.getConnection();
            ps= conn.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMeteData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();
            if(rs.next()){
                Customer cust = new Customer();
                for(int i=0;i<columnCount;i++){
                  Object columnvalue=rs.getObject(i+1);
                  //获取每个列的列名
                    String columnName=rsmd.getColumnName(i+1);
                    //给cust对象指定的columnName属性,赋值columValue,通过反射
                    Field field=Customer.class.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(cust,columnvalue);
                }
                return  cust;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCutils.closeResource(ps,conn,rs);
        }
        return null;
    }
    @Test
    public void testQuery1() {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        try {
            //1.获取数据库连接
            conn = JDBCutils.getConnection();
            //2.预编译sql语句,获取PreparedStatement对象
            String  sql="select id,name,pwd from user where id =?";
            ps = conn.prepareStatement(sql);
            ps.setObject(1,2);
            //执行,并返回结果集
            resultSet = ps.executeQuery();
            //处理结果集
            if(resultSet.next()){//.next()方法判断结果集的下一条是否有数据,如果有数据返回true并指针下移,如果无返回false;
                //获取当前这条数据的各个字段值
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                String pwd = resultSet.getString(3);
                //方式一:
    //            System.out.println("id =" + id +",name = " + name + "pwd =" + pwd );
                //方式二:
    //          Object[] data= new Object[]{id,name,pwd};
                //方式三:将数据封装为一个对象(推荐)
                Customer customer = new Customer(id, name, pwd);
                System.out.println(customer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCutils.closeResource(ps,conn,resultSet);
        }
    }
}
7.2 查常见问题

 有时候数据库表的结构会发生变化,出现数据不对应的问题。
 
 
 可以通过起别名的方式解决
 
 但还是会报错?
 为什么?
 改为获取列的别名。
 
7.3图解查询操作的流程

7.4用泛型实现任意表的查询
泛型复习
 泛型方法声明
 1.只能查询一条数据
 public <T2> void printArray(T2[] arr){
       for (int i = 0; i < arr.length; i++) {
             System.out.println(arr[i]);
   } }
反射复习
import org.junit.Test;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/**
 * @description:使用PreparedStatement实现针对不同的通用的查询操作
 * @author: Ada
 * @time: 2022/3/14
 */
public class PreparedStatementQueryTest {
    @Test
    public void testGetInstance() throws Exception {
        String sql="select id,name,pwd from user where id=?";
        User user=getInstance(User.class,sql,2);
        System.out.println(user);
    }
    public <T> T getInstance(Class<T> clazz,String sql, Object...args) throws Exception {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn = JDBCutils.getConnection();
            ps= conn.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMeteData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();
            if(rs.next()){
                T t = clazz.newInstance();
                for(int i=0;i<columnCount;i++){
                    Object columnvalue=rs.getObject(i+1);
                    //获取每个列的列名
                    String columnName=rsmd.getColumnName(i+1);
                    //给cust对象指定的columnName属性,赋值columValue,通过反射
                    Field field=clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnvalue);
                }
                return  t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCutils.closeResource(ps,conn);
        }
        return null;
    }
}
2.可以查询多条数据
import org.junit.Test;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
 * @description:使用PreparedStatement实现针对不同的通用的查询操作
 * @author: Ada
 * @time: 2022/3/14
 */
public class PreparedStatementQueryTest {
    @Test
    public void testGetInstance() throws Exception {
        String sql="select id,name,pwd from user where id < ?";
        List<User> list = getForList(User.class, sql, 4);
        Iterator<User> iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
    public <T> List<T> getForList(Class<T> clazz, String sql, Object...args) throws Exception {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn = JDBCutils.getConnection();
            ps= conn.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMeteData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();
            //创建集合对象
            ArrayList<T> list = new ArrayList<T>();
            while (rs.next()){
                T t = clazz.newInstance();
                for(int i=0;i<columnCount;i++){
                    Object columnvalue=rs.getObject(i+1);
                    //获取每个列的列名
                    String columnName=rsmd.getColumnName(i+1);
                    //给cust对象指定的columnName属性,赋值columValue,通过反射
                    Field field=clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnvalue);
                }
                list.add(t);
            }
            return  list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCutils.closeResource(ps,conn);
        }
        return null;
    }
}
7.5使用PreparedStatement解决SQL注入问题
@Test
    public void testLogin() throws Exception {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String user= scanner.nextLine();
        System.out.println("请输入密码:");
        String password = scanner.nextLine();
        //SELECT name,password from user where user ='1' or AND password = '=1 or '1' ='1'
        String sql="SELECT name,password from user where user =? and password =? ";
        User returnUser = getInstance(User.class, sql, user, password);
        if(returnUser !=null){
            System.out.println("登录成功");
        }else {
            System.out.println("用户名不存在或者密码错误");
        }

 使用PreparedStatement输入这句话就会显示登录失败,
 成功防止sql注入。
7.6Statement和PreparedStatement的区别
除了解决Statement的拼串,sql问题之外,PreparedStatement还有那些好处呢?
1.PreparedStatement操作Blob的数据,而Statement做不到
2.PreparesStatemet可以实现更高校的批量操作。
8.向数据表中插入Blob类型数据

 数据库表设计的有Blob类型的字段
 
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
 * @description:
 * @author: Ada
 * @time: 2022/3/15
 */
public class BlobTest {
    //向数据customer中插入Blob类型的字段
    @Test
    public void testInsert() throws SQLException, FileNotFoundException {
        Connection conn= JDBCutils.getConnection();
        System.out.println(conn);
        String sql="insert into customers(name,email,birth,photo) values(?,?,?,?)";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setObject(1,"章子怡");
        ps.setObject(2,"zhang@qq.com");
        ps.setObject(3,"1992-09-08");
        FileInputStream is = new FileInputStream(new File("src/main/resources/A.jpg"));
        ps.setBlob(4,is);
        ps.execute();
        JDBCutils.closeResource(ps,conn);
    }
}

8.1从数据表中读取Blob类型的数据
import org.junit.Test;
import java.io.*;
import java.sql.*;
/**
 * @description:
 * @author: Ada
 * @time: 2022/3/15
 */
public class BlobTest {
    //向数据customer中插入Blob类型的字段
    @Test
    public void testInsert() throws SQLException, FileNotFoundException {
        Connection conn= JDBCutils.getConnection();
        System.out.println(conn);
        String sql="insert into customers(name,email,birth,photo) values(?,?,?,?)";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setObject(1,"章子怡");
        ps.setObject(2,"zhang@qq.com");
        ps.setObject(3,"1992-09-08");
        FileInputStream is = new FileInputStream(new File("src/main/resources/A.jpg"));
        ps.setBlob(4,is);
        ps.execute();
        JDBCutils.closeResource(ps,conn);
    }
    //查询数据表customer中Blob的字段
    @Test
    public void testQuery() throws Exception {
        Connection conn = BJDBCutils.getConnection();
        String sql="select id, name,email,birth,photo from customers where id=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setInt(1,16);
        ResultSet rs = ps.executeQuery();
        if(rs.next()){
           // 方式一:
//
//            int anInt = rs.getInt(1);
//            String string = rs.getString(2);
//            String string1 = rs.getString(3);
//            Date date = rs.getDate(4);
//            Blob blob = rs.getBlob(5);
            //方式二:
            int id = rs.getInt("id");
            String name = rs.getString("name");
            String email= rs.getString("email");
            Date birth = rs.getDate("birth");
            Customers cust = new Customers(id, name, email, birth);
            //将Blob类型的字段下载下来,以文件的方式保存到本地
            Blob photo = rs.getBlob("photo");
            InputStream is= photo.getBinaryStream();
            FileOutputStream fos = new FileOutputStream("src/main/resources/zhangyuhao.jpg");
            System.out.println(cust);
            byte[] buffer = new byte[1024];
            int len;
            while((len=is.read(buffer))!=-1){
                fos.write(buffer,0,len);
            }
            is.close();
            fos.close();
            BJDBCutils.closeResource(ps,conn,rs);
        }
    }
}
9.批量插入操作
9.1用PreparementStatement实现批量插入操作
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
 * @description:使用PreparesStatement实现批量数据的操作
 * @author: Ada
 * @time: 2022/3/15
 *
 *
 *
 * update ,delete本身就具有批量操作的效果
 * 此时的批量操作,主要指的是批量插入,使用PreparedStatement如何实现更高效的批量插入?
 *
 *
 * 方式一:S使用Statement
 * Connection conn=BBJDBCutils.getConnection();
 * Statement st=conn.createStatement();
 * for(int i=1;i<=2000;i++){
 *     String sql="insert into goods(name)values('name_"+i+"")";
 *     st.execute(sql);
 * }
 *
 */
public class InsertTest {
    //用PreparedStatement实现批量操作
    @Test
    public void testInsert1()  {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            long start = System.currentTimeMillis();
            conn = BJDBCutils.getConnection();
            String sql="insert into goods(name)values(?)";
             ps = conn.prepareStatement(sql);
            for(int i=1;i<=20000;i++){
                ps.setString(1,"name_"+i);
                ps.execute();
            }
          long end=System.currentTimeMillis();
            System.out.println("花费时间为:"+(end-start));
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            BJDBCutils.closeResource(ps,conn);
        }
    }
}

 
 用truncate清空数据库
9.2用Batch提高效率
@Test
    public void insert1(){
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            long start = System.currentTimeMillis();
            conn = BJDBCutils.getConnection();
            String sql="insert into goods(name)values(?)";
            ps = conn.prepareStatement(sql);
            for(int i=1;i<=20000;i++){
                ps.setString(1,"name_"+i);
                //1.赞sql
                ps.addBatch();
                if(i%500==0){
                    //2.执行batch
                    ps.executeBatch();
                    //3.清空batch
                    ps.clearBatch();
                }
            }
            long end=System.currentTimeMillis();
            System.out.println("Batch花费时间为:"+(end-start));
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            BJDBCutils.closeResource(ps,conn);
        }
    }
9.3setAutoCommit提高效率(最高效)
@Test
    public void insert1(){
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            long start = System.currentTimeMillis();
            conn = BJDBCutils.getConnection();
           conn.setAutoCommit(false);
            String sql="insert into goods(name)values(?)";
            ps = conn.prepareStatement(sql);
            for(int i=1;i<=20000;i++){
                ps.setString(1,"name_"+i);
                //1.赞sql
                ps.addBatch();
                if(i%500==0){
                    //2.执行batch
                    ps.executeBatch();
                    //3.清空batch
                    ps.clearBatch();
                }
            }
           conn.commit();
            long end=System.currentTimeMillis();
            System.out.println("Batch花费时间为:"+(end-start));
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            BJDBCutils.closeResource(ps,conn);
        }
    }
数据库事物的引入

 
 总和应该是2000现在是1900.
1.考虑事务以后的代码实现
//考虑数据库事务后的转账操作
    @Test
    public void testUpdateWithTx(){
        Connection conn=null;
        try {
            conn= BJDBCutils.getConnection();
            System.out.println(conn.getAutoCommit());//true默认情况下是true
            //1.取消数据的自动提交
          conn.setAutoCommit(false);
            String sql1="update user_table set balance = balance-100 where user =?";
            update1(conn,sql1,"AA");
            System.out.println(10/0);
            String sql2="update user_table set  balance = balance+100 where user =?";
            update1(conn,sql2,"BB");
            System.out.println("转账成功");
           //2.提交数据
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //3.回滚数据
            try {
                conn.rollback();
                System.out.println("转账失败");
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            BJDBCutils.closeResource(null,conn);
        }
    }
    public int update1(Connection conn, String sql,Object ...args){
        PreparedStatement ps=null;
        //1.获取数据库连接
        try {
            //2.预编译sql语句,返回PreparedStatement的实例
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            //4.执行
            return   ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            BJDBCutils.closeResource(ps,null);
        }
        return 0;
    }
2.包的使用

Dao及实现类
package com.ada.dao;
import com.ada.util.BJDBCutils;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
 * @description:
 * @author: Ada
 * @time: 2022/3/16
 * 封装了针对于数据表的通用的操作
 */
public class BaseDao {
     //通用的增删改
    public int update1(Connection conn, String sql, Object ...args){
        PreparedStatement ps=null;
        //1.获取数据库连接
        try {
            //2.预编译sql语句,返回PreparedStatement的实例
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            //4.执行
            return   ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            BJDBCutils.closeResource(ps,null);
        }
        return 0;
    }
    //通用的查询操作,用于返回数据表的一条记录(version2.0,考虑上事务)
    public <T> T getInstance(Connection conn,Class<T> clazz, String sql, Object...args){
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            ps= conn.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMeteData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();
            //创建集合对象
            ArrayList<T> list = new ArrayList<T>();
            if(rs.next()){
                T t = clazz.newInstance();
                for(int i=0;i<columnCount;i++){
                    Object columnvalue=rs.getObject(i+1);
                    //获取每个列的列名
                    String columnName=rsmd.getColumnName(i+1);
                    //给cust对象指定的columnName属性,赋值columValue,通过反射
                    Field field=clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnvalue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BJDBCutils.closeResource(ps,null);
        }
        return null;
    }
    //返回多个对象的
    public <T> List<T> getForList(Connection conn, Class<T> clazz, String sql, Object...args)  {
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            ps= conn.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMeteData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();
            //创建集合对象
            ArrayList<T> list = new ArrayList<T>();
            while (rs.next()){
                T t = clazz.newInstance();
                for(int i=0;i<columnCount;i++){
                    Object columnvalue=rs.getObject(i+1);
                    //获取每个列的列名
                    String columnName=rsmd.getColumnName(i+1);
                    //给cust对象指定的columnName属性,赋值columValue,通过反射
                    Field field=clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnvalue);
                }
                list.add(t);
            }
            return  list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
                BJDBCutils.closeResource(ps,null);
        }
        return null;
    }
    //用于查询特殊值的方法
    public <E> E getValue(Connection conn,String sql,Object...args){
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            ps = conn.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            if(rs.next()){
              return  (E)rs.getObject(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            BJDBCutils.closeResource(ps,null,rs);
        }
        return null;
    }
}
package com.ada.dao;
import com.ada.bean.Customers;
import java.sql.Connection;
import java.util.Date;
import java.util.List;
/**
 * @description:
 * @author: Ada
 * @time: 2022/3/17
 *
 * 此接口用于规范对于customers表的常规操作
 */
public interface CustomerDao {
    /*
    * 将cust对象添加到数据库中
    * */
    void insert(Connection conn,Customers cust);
    /*
      针对指定的id,删除表中的一条记录
    * */
    void deleteById(Connection conn,int id);
    void updateById(Connection conn,Customers cust);
    Customers getCustomerById(Connection conn,int id);
    /*
    * 查询表中的所有记录
    * */
    List<Customers> getAll(Connection conn);
    //返回数据表中数据的条目数
    Long getCount(Connection conn);
    //返回数据表中最大的生日
    Date getMaxBirth(Connection conn);
}
package com.ada.dao;
import com.ada.bean.Customers;
import java.sql.Connection;
import java.util.Date;
import java.util.List;
/**
 * @description:
 * @author: Ada
 * @time: 2022/3/17
 */
public class CustomerDAOImp1 extends BaseDao implements  CustomerDao {
    @Override
    public void insert(Connection conn, Customers cust) {
        String sql="insert into customers(name,email,birth) values(?,?,?)";
        update1(conn,sql,cust.getName(),cust.getEmail(),cust.getBirth());
    }
    @Override
    public void deleteById(Connection conn, int id) {
        String sql="delete from customers where id= ?";
        update1(conn,sql, id);
    }
    @Override
    public void updateById(Connection conn, Customers cust) {
        String sql="update customers set name=?,email=?,birth=? where id=?";
        update1(conn,sql,cust.getName(),cust.getEmail(),cust.getBirth(),cust.getId());
    }
    @Override
    public Customers getCustomerById(Connection conn, int id) {
        String sql="select id,name,email,birth from customers where id =?";
        Customers customer = getInstance(conn, Customers.class, sql, id);
        return customer;
    }
    @Override
    public List<Customers> getAll(Connection conn) {
        String sql="select id,name,email,birth from customers";
        List<Customers> customersList = getForList(conn, Customers.class, sql);
        return customersList;
    }
    @Override
    public Long getCount(Connection conn) {
        String sql="select count(*) from customers";
         return getValue(conn, sql);
    }
    @Override
    public Date getMaxBirth(Connection conn) {
        String sql="select max(birth) from customers";
       return getValue(conn,sql);
    }
}

3.cp30数据库连接数据池的两种实现方式
做之前要
 1.添加驱动
 2.把他放到路径里面
 File–>Project Structure–>Modules–>点加号选择驱动的路径即可
 

package com.ada.connection;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;
import org.junit.Test;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
/**
 * @description:
 * @author: Ada
 * @time: 2022/3/17
 */
public class C3P0Test {
    @Test
    public void testGetConnection() throws Exception {
       //获取C3P0数据库连接池
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        cpds.setDriverClass( "com.mysql.cj.jdbc.Driver" ); //loads the jdbc driver
        cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/test" );
        cpds.setUser("root");
        cpds.setPassword("");
        //通过设置相关的参数,对数据库连接池进行管理
        //设置初始时数据库连接池的连接数
       cpds.setInitialPoolSize(10);
        Connection conn = cpds.getConnection();
        System.out.println(conn);
        //销毁c3p0的连接池
      //  DataSources.destroy(cpds);
    }
    //方式二:使用配置文件
    @Test
    public void testConnection() throws SQLException {
        ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");
        Connection conn = cpds.getConnection();
        System.out.println(conn);
    }
}

 配置文件放这里
 
user=root
password=
url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&rewriteBatchedStatements=true
driver=com.mysql.cj.jdbc.Driver
4.DBCP数据库连接池的两种实现方式
package com.ada.connection;
import com.mchange.v2.c3p0.DataSources;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;
import javax.activation.DataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
 * @description:
 * 测试DBCP的数据库连接池技术
 * @author: Ada
 * @time: 2022/3/17
 */
public class DBCPTest {
   @Test
    public void testGetConnection() throws SQLException {
        //创建了DBCP的数据库连接池
        BasicDataSource source= new BasicDataSource();
        //设置基本信息
        source.setDriverClassName("com.mysql.jdbc.Driver");
        source.setUrl("jdbc:mysql:///test");
        source.setUsername("root");
        source.setPassword("");
        //还可以设置其他涉及数据库连接池管理的相关属性
        source.setInitialSize(10);
        source.setMaxActive(10);
        Connection conn = source.getConnection();
        System.out.println(conn);
    }
    //方式二:使用配置文件
    @Test
    public void  test1GetConnection() throws Exception {
        Properties pros = new Properties();
        //方式一:
       // InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
        FileInputStream is = new FileInputStream(new File("src/main/resources/dbcp.properties"));
        pros.load(is);
        javax.sql.DataSource source = BasicDataSourceFactory.createDataSource(pros);
        Connection conn = source.getConnection();
        System.out.println(conn);
    }
}
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=
initialSize=10

 优化后的代码如下:不能每次都新建一个连接池,所以放到静态代码块里面,每次只执行一次。
package com.ada.connection;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.DataSources;
import org.junit.Test;
import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/**
 * @description:
 * @author: Ada使用Druid数据库连接池技术
 * @time: 2022/3/17
 */
public class DruidTest {
    private static DataSource source;
    static{
        try {
            Properties pros = new Properties();
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
            pros.load(is);
           source = DruidDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Test
    public void getConnection() throws Exception {
        Connection conn = source.getConnection();
        System.out.println(conn);
    }
}
5.Druid连接数据库的实现
package com.ada.connection;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.DataSources;
import org.junit.Test;
import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/**
 * @description:
 * @author: Ada使用Druid数据库连接池技术
 * @time: 2022/3/17
 */
public class DruidTest {
    private static DataSource source;
    static{
        try {
            Properties pros = new Properties();
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
            pros.load(is);
           source = DruidDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Test
    public void getConnection() throws Exception {
        Connection conn = source.getConnection();
        System.out.println(conn);
    }
}

url=jdbc:mysql:///test
username=root
password=
driverClassName=com.mysql.cj.jdbc.Driver
initialSize=10
maxActive=10









