Jdbc入门

Jdbc本质(一套接口)

1.jdbc 是什么?

Java DataBase Connectivity(Java语言连接数据库)

2.jdbc的本质是什么?

jdbc是sun 公司指定的一套接口。 接口都有调用者和实现者。
面向接口调用、面向接口写实现类,这都属于面向接口编程。
接i都有调用者和实现者。 面向接口调用、面向接口写实现类,这都属于面向接口编程。
在这里插入图片描述

思考:为什么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需要加双引号而有些不需要

双引号表示字符串
比如
定义 int a(string s)
调用时可以 a(“asdas”)
“asdas”就表示一个字符串
当然也可以
string str=“asdasd”
a(str)这样使用

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查

getDeclaredFiled 仅能获取类本身的属性成员(包括私有、共有、保护) getField 仅能获取类(及其父类可以自己测试)
public属性成员

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 查常见问题

针对表的字段名与类的属性名不相同的情况;
1.必须声明sql时,使用类的属性名来命名字段的别名。
2.使用ResultSetMetaData时,需要使用getColumnLabel() 来替换getColumnName()来获取别名。 说明:如果sql中没有给字段取别名,getColumnLabel()获取的就是列名。

在这里插入图片描述
有时候数据库表的结构会发生变化,出现数据不对应的问题。
在这里插入图片描述
在这里插入图片描述
可以通过起别名的方式解决
在这里插入图片描述
但还是会报错?
为什么?
改为获取列的别名。
在这里插入图片描述

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提高效率

批量插入方式二:
//用addBathch(),excuteBatch(),clearBatch()实现批量插入提升效率
//mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。
// * ?rewriteBatchedStatements=true 写在配置文件的url后面

@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);
        }

    }

数据库事物的引入

1.事务处理(事务操作):保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)**到最初状态。
2.数据一旦提交,就不可回滚。(回滚是回滚到最近一个提交之前)
3.
DDL操作一旦执行,都会自动提交
DML默认情况下一旦执行,就会自动提交
我们可以通过set autocomit = false/0 的方式取消DML的自动提交
默认在关闭连接时,会自动地提交数据

在这里插入图片描述
在这里插入图片描述
总和应该是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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值