程序员社区

JDBC从零开始的保姆级教程!!!

JDBC从零开始的保姆级教程!!!

  • JAVA与数据库的连接方式
  • JDBC体系结构
  • JDBC程序编写步骤
  • 获取数据库连接方式一
  • 数据库连接方式二
  • 数据库连接的方式三
  • 数据库连接方式四
  • 数据库连接方式五---final版本
    • final版的好处
  • 操作和访问数据库
    • DriverManger : 驱动管理对象
    • Connection :数据库连接对象
    • Statement : 执行sql的对象
    • ResultSet: 结果集对象,封装查询结果
  • JDBC工具类----JDBCUtils
  • 利用工具类来实现一个检测登陆是否成功的案例
    • PreparedStatement : 执行sql的对象,避免SQL注入问题
  • JDBC管理事务
  • 数据库连接池
    • 连接池实现
    • c3p0连接池
    • Druid连接池
    • 工具类
    • JDBC数据的批处理操作
  • Spring的Template
    • 执行DML语句
    • 执行DQL语句
    • 注意:

JAVA与数据库的连接方式

在这里插入图片描述

JDBC体系结构

在这里插入图片描述

JDBC程序编写步骤

在这里插入图片描述

获取数据库连接方式一

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

public class MAIN
{
    public static void main(String[] args) throws ClassNotFoundException, SQLException
    {
    //获取driver的实现类对象
   Driver driver=new com.mysql.jdbc.Driver();
   //jbdc:mysql :协议
   //localhost: ip地址
   // 3306: 默认mysql的端口号
   //test1: test1数据库
   String url="jdbc:mysql://localhost:3306/test1";
   //将用户名和密码封装在properties中
        Properties   info=new Properties();
        info.setProperty("user","root");
        info.setProperty("password","126433");

        Connection conn=driver.connect(url,info);
        System.out.println(conn);
    }
}

数据库连接方式二

对方式一的迭代,避免第三方的api,使得程序有更好的可移植性

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

public class MAIN
{
    public static void main(String[] args) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
        //1.获取Driver实现类对象,使用反射
       Class clazz=Class.forName("com.mysql.jdbc.Driver");
       Driver driver=(Driver)clazz.newInstance();

   String url="jdbc:mysql://localhost:3306/test1";

        Properties   info=new Properties();
        info.setProperty("user","root");
        info.setProperty("password","126433");

        Connection conn=driver.connect(url,info);
        System.out.println(conn);
    }
}

数据库连接的方式三

使用DriverManger替换Driver

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

public class MAIN
{
    public static void main(String[] args) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
          //1.提供另外三个连接的基本信息
        String url="jdbc:mysql://localhost:3306/test1";
        String user="root";
        String password="126433";
        
        //2.获取Driver实现类对象,使用反射
       Class clazz=Class.forName("com.mysql.jdbc.Driver");
       Driver driver=(Driver)clazz.newInstance();
        //注册驱动
        DriverManager.registerDriver(driver);
        
        //获取连接
        Connection conn=DriverManager.getConnection(url,user,password);
        System.out.println(conn);
    }
}

数据库连接方式四

可以只是加载驱动,而非显示的注册驱动了

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

public class MAIN
{
    public static void main(String[] args) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
        //1.提供另外三个连接的基本信息
        String url="jdbc:mysql://localhost:3306/test1";
        String user="root";
        String password="126433";

        //2.加载Driver
       Class clazz=Class.forName("com.mysql.jdbc.Driver");
      //相较于方式三,可以省略如下的操作:
      /* Driver driver=(Driver)clazz.newInstance();
        //注册驱动
        DriverManager.registerDriver(driver);*/
        
        //获取连接
        Connection conn=DriverManager.getConnection(url,user,password);
        System.out.println(conn);
    }
}

为什么可以省略呢?

因为在mysql的Driver实现类中,静态代码块声明了如下的操作:
在这里插入图片描述

数据库连接方式五—final版本

将数据库连接需要的四个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接

配置文件:

user=root
password=126433
url=jdbc:mysql://localhost:3306/test1
driverClass=com.jdbc.mysql.Driver

在这里插入图片描述

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class MAIN
{
    public static void main(String[] args) throws Exception{
          //MAIN是当前的类
        InputStream is=MAIN.class.getClassLoader().getResourceAsStream("jdbc.properities");
        Properties pros=new Properties();
        pros.load(is);

        String user=pros.getProperty("user");
        String password=pros.getProperty("password");
        String url=pros.getProperty("url");
        String driverClass=pros.getProperty("driverClass");

        //加载驱动
        Class.forName(driverClass);

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

final版的好处

实现了数据和代码的分离,实现了解耦

如果需要修改配置文件信息,可以避免程序重新打包


操作和访问数据库

在这里插入图片描述

在这里插入图片描述


DriverManger : 驱动管理对象

功能1:
在这里插入图片描述

功能2:

在这里插入图片描述
演示:

    public static void main(String[] args) throws Exception {
      //1.导入驱动jar包
        //2.注册驱动
        //java5版本后可以省略下面这行代码
        Class.forName("com.mysql.jdbc.Driver");
        //3.获取数据库连接对象
        //Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test1","root","126433");
        Connection conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
        //4.定义sql语句
        //注意: 嵌套字符串,外双里单
        //这里被双引号包裹的sql语句结尾不用加分号
        String sql="update depart set  name='大忽悠总裁办' where wID=105";
        //5.获取执行sql的对象       Statement
        Statement stmt=conn.createStatement();
        //6.执行sql
        int count=stmt.executeUpdate(sql);
        //7.处理结果
        System.out.println(count);
        //8.释放资源
        stmt.close();
        conn.close();
    }

在这里插入图片描述


Connection :数据库连接对象

在这里插入图片描述


Statement : 执行sql的对象

在这里插入图片描述

DDL语句默认返回0

insert语句练习:

public class newMain {
    public static void main(String[] args)
    {
        Connection conn=null;
        Statement stmt=null;
          //1.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //2.定义sql语句
        String sql="INSERT INTO depart VALUES(110,'小朋友副总裁办')";
        try {
            //3.获取connection对象
            conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
            //4.获取sql对象,执行Statement
             stmt=conn.createStatement();
            //5.执行sql
            int count=stmt.executeUpdate(sql);
            if(count>0)
                System.out.println("添加成功!!");
            else
                System.out.println("添加失败");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //7.释放资源
            //避免空指针异常
            if(stmt!=null) {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }

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

在这里插入图片描述

update语句练习:

public class newMain {
    public static void main(String[] args)
    {
        Connection conn=null;
        Statement stmt=null;
         //1.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取connection对象
             conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
             //3.定义sql语句
            String sql="update depart set name='大忽悠和小朋友工作室' where wID=101";
            //4.获取sql对象
            stmt=conn.createStatement();
            //5.执行sql语句
            int count=stmt.executeUpdate(sql);
            if(count>0)
                System.out.println("修改成功");
            else
                System.out.println("修改失败");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //7.释放资源
            if(stmt!=null)
            {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null)
            {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
}

在这里插入图片描述

delete语句练习:

public class newMain {
    public static void main(String[] args)
    {
        Connection conn=null;
        Statement stmt=null;
         //1.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取connection对象
             conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
             //3.定义sql语句
            String sql="delete from depart where name like '%后%'";
            //4.获取sql对象
            stmt=conn.createStatement();
            //5.执行sql语句
            int count=stmt.executeUpdate(sql);
            if(count>0)
                System.out.println("删除成功");
            else
                System.out.println("删除失败");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //7.释放资源
            if(stmt!=null)
            {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null)
            {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

    }
}

在这里插入图片描述

DDL语句之建表练习:

public class newMain {
    public static void main(String[] args)
    {
        Connection conn=null;
        Statement stmt=null;
         //1.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取connection对象
             conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
             //3.定义sql语句
            String sql="create table newDepart(newWID int primary key,newDepartName varchar(20))";
            //4.获取sql对象
            stmt=conn.createStatement();
            //5.执行sql语句
            int count=stmt.executeUpdate(sql);
            System.out.println("DDL语句默认返回: "+count);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //7.释放资源
            if(stmt!=null)
            {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null)
            {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
}

在这里插入图片描述


ResultSet: 结果集对象,封装查询结果

在这里插入图片描述

演示:

public class newMain {
    public static void main(String[] args)
    {
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        //1.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取conncetion对象
            conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
            //3.定义sql语句---查询语句
            String sql="select *from depart";
            //4.获取执行sql的对象
            stmt=conn.createStatement();
            //5.执行sql语句---返回一个查询到的结果集
            rs=stmt.executeQuery(sql);
            //6.处理结果
            //6.1让游标向下移动一行
            rs.next();
            //6.2获取资源
            int wID=rs.getInt(1);
            String name=rs.getString("name");
            System.out.println("查询到的部门编号:"+wID+"     查询到部门名称:"+name);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //7.释放资源
            //最后打开的先释放
            try {
                if(rs!=null)
                    rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if(stmt!=null)
                    stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if(conn!=null)
                    conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

注意:
在这里插入图片描述
在这里插入图片描述
查询所有记录的正确演示:

public class newMain {
    public static void main(String[] args)
    {
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        //1.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取conncetion对象
            conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
            //3.定义sql语句---查询语句
            String sql="select *from depart";
            //4.获取执行sql的对象
            stmt=conn.createStatement();
            //5.执行sql语句---返回一个查询到的结果集
            rs=stmt.executeQuery(sql);
            //6.处理结果
            //循环判断游标是否是最后一行的末尾
            while(rs.next())
            {
                //6.2获取资源
                int wID=rs.getInt(1);
                String name=rs.getString("name");
                System.out.println("查询到的部门编号:"+wID+"     查询到部门名称:"+name);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //7.释放资源
            //最后打开的先释放
            try {
                if(rs!=null)
                    rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if(stmt!=null)
                    stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if(conn!=null)
                    conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

在这里插入图片描述


JDBC工具类----JDBCUtils

目的:简化书写
分析:

  1. 注册驱动也抽取一下
  2. 抽取一个方法来获取连接对象
    需求:不想传递参数,还要保证工具类的通用性
    解决: 配置文件
    jdbc.properties
    url=
    user=
    password=
  3. 抽取一个方法来释放资源

代码演示:

JDBCUtil工具类:

package tuil;

import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

/*
JDBC工具类

* */
public class JDBCUtil
{
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    //文件的读取只需要读取一次即可拿到配置文件中的信息
    //使用静态代码块--->随着类的加载而首选加载,并且只执行一次
    static {
             //读取资源文件,获取值
        //1.创建Properties集合类
        Properties pro=new Properties();
        //2.加载文件
        try {
            //获取src下文件路径的方法----->ClassLoader 类加载器
            //作用: (1)加载字节码文件进内存
            //(2):获取src下资源文件的路径
            ClassLoader cl=JDBCUtil.class.getClassLoader();
            //返回一个URL对象,URL:统一资源定位符,可以用来获取文件的绝对路径
              URL res=cl.getResource("jdbc.properties");
              String path=res.getPath();
            pro.load(new FileReader(path));

        } catch (IOException e) {
            e.printStackTrace();
        }
        //3.获取数据,赋值
        url=pro.getProperty("url");
        user=pro.getProperty("user");
        password=pro.getProperty("password");
        driver=pro.getProperty("driver");
        //4.注册驱动
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

  //设置所有方法为静态的,方便调用
    //1.获取连接,返回连接对象
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }
    //2.释放资源
    public static void close(Statement stmt,Connection conn)
    {
        if(stmt!=null)
        {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null)
        {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    //释放资源的重载版本
    public static void close(ResultSet rs,Statement stmt, Connection conn)
    {
        if(rs!=null)
        {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt!=null)
        {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null)
        {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

jdbc.properties配置文件:

url=jdbc:mysql:///test1
user=root
password=126433
driver=com.mysql.jdbc.Driver

newMian测试主类:

import tuil.JDBCUtil;

import java.sql.*;

public class newMain {
    public static void main(String[] args)
    {
        try {
            Connection conn=JDBCUtil.getConnection();
            Statement stmt=conn.createStatement();
            String sql="update depart set name='大忽悠研发部' where wID=103";
            stmt.executeUpdate(sql);
            JDBCUtil.close(stmt,conn);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

结果演示:

在这里插入图片描述


利用工具类来实现一个检测登陆是否成功的案例

login类

package tuil;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

public class loginMain {
    public static void main(String[] args)
    {
         //1.键盘录入,接收用户名和密码
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入用户名: ");
        String username=sc.next();
        System.out.println("请输入密码: ");
        String password=sc.next();
        //2.调用方法
        boolean flag=new loginMain().login(username,password);
        if(flag)
            System.out.println("登陆成功");
        else
            System.out.println("登陆失败");
    }
    /*
    * 登陆方法
    * */
    public boolean login(String userName,String password)  {
        if(userName==null||password==null)
            return false;
        //连接数据库判断是否登陆成功
        //1.获取连接
        Connection conn= null;
        Statement stmt=null;
        ResultSet res=null;
        try {
            conn = JDBCUtil.getConnection();
            //2.定义sql
            String sql="select * from login where Username='"+userName+"'and password='"+password+"'";
            //3.获取执行sql的对象
            stmt=conn.createStatement();
            //4.执行查询
            res=stmt.executeQuery(sql);
            //5.判断
            return res.next();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(res,stmt,conn);
        }
        return false;
    }
}

配置文件信息修改和对应数据库信息展示
在这里插入图片描述
在这里插入图片描述
执行效果演示

在这里插入图片描述

在这里插入图片描述


PreparedStatement : 执行sql的对象,避免SQL注入问题

PreparedStatement的父类是Statement

在这里插入图片描述
在这里插入图片描述

检测登陆案例SQL注入问题修正版本

只针对login类进行代码处理:

package tuil;

import java.sql.*;
import java.util.Scanner;

public class loginMain {
    public static void main(String[] args)
    {
         //1.键盘录入,接收用户名和密码
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入用户名: ");
        String username=sc.next();
        System.out.println("请输入密码: ");
        String password=sc.next();
        //2.调用方法
        boolean flag=new loginMain().login(username,password);
        if(flag)
            System.out.println("登陆成功");
        else
            System.out.println("登陆失败");
    }
    /*
    * 登陆方法
    * */
    public boolean login(String userName,String password)  {
        if(userName==null||password==null)
            return false;
        //连接数据库判断是否登陆成功
        //1.获取连接
        Connection conn= null;
        PreparedStatement pstmt=null;
        ResultSet res=null;
        try {
            conn = JDBCUtil.getConnection();
            //2.定义sql
            String sql="select * from login where Username= ? and password= ?";
            //3.获取执行sql的对象
            pstmt=conn.prepareStatement(sql);
            //给?赋值
            pstmt.setString(1,userName);
            pstmt.setString(2,password);
            //4.执行查询---不需要传递sql,不然就调用其父类的函数了
            res=pstmt.executeQuery();
            //5.判断
            return res.next();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //父类指针指向子类引用
            JDBCUtil.close(res,pstmt,conn);
        }
        return false;
    }
}

在这里插入图片描述


JDBC管理事务

在这里插入图片描述

演示为什么要使用事务,这里使用一个转账案例作为演示:

数据库环境搭建:
在这里插入图片描述
大忽悠转账给小朋友500:

正常没有出现异常的情况,转账成功

package tuil;

import java.sql.*;
import java.util.Scanner;

public class loginMain {
    public static void main(String[] args)
    {
          Scanner sc=new Scanner(System.in);
        System.out.println("转账者:");
        String Giver=sc.nextLine();
        System.out.println("收款者:");
        String Revicer=sc.nextLine();
        System.out.println("转账金额:");
        int money=0;
        if(sc.hasNextInt())
        money=sc.nextInt();
        boolean flag=new loginMain().giveMoney(Giver,Revicer,money);
          if(flag)
              System.out.println("转账成功");
          else
              System.out.println("转账失败");
    }
    /*
    * 大忽悠转账给小朋友500块
    * */
    public boolean giveMoney(String Giver,String Revicer,int money)  {
        if(Giver==null||Revicer==null||money<0)
            return false;
        //连接数据库判断是否登陆成功
        //1.获取连接
        Connection conn= null;
        PreparedStatement pstmt1=null;
        PreparedStatement pstmt2=null;
        try {
            conn = JDBCUtil.getConnection();
            //2.定义sql
            String sql1="update login set money=money-? where name= ?";
            String sql2="update login set money=money+? where name= ?";
            //3.获取执行sql的对象
               pstmt1=conn.prepareStatement(sql1);
               pstmt2=conn.prepareStatement(sql2);
            //给?赋值
            pstmt1.setInt(1,500);
            pstmt1.setString(2,"大忽悠");
            pstmt2.setInt(1,500);
            pstmt2.setString(2,"小朋友");
            //4.执行
            pstmt1.executeUpdate();
            pstmt2.executeUpdate();
            return true;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //父类指针指向子类引用
            JDBCUtil.close(pstmt1,conn);
            JDBCUtil.close(pstmt2,conn);
        }
        return false;
    }
}

在这里插入图片描述
出现异常的情况下,转账到一半就会终止,得到的结果会出现问题

            //4.执行
            pstmt1.executeUpdate();
            //异常的出现
            String s=null;
            s.getBytes(StandardCharsets.UTF_8);
              pstmt2.executeUpdate();

在这里插入图片描述
这个时候,转账出现问题,需要通过事务来进行解决

package tuil;

import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.Scanner;

public class loginMain {
    public static void main(String[] args)
    {
          Scanner sc=new Scanner(System.in);
        System.out.println("转账者:");
        String Giver=sc.nextLine();
        System.out.println("收款者:");
        String Revicer=sc.nextLine();
        System.out.println("转账金额:");
        int money=0;
        if(sc.hasNextInt())
        money=sc.nextInt();
        boolean flag=new loginMain().giveMoney(Giver,Revicer,money);
          if(flag)
              System.out.println("转账成功");
          else
              System.out.println("转账失败");
    }
    /*
    * 大忽悠转账给小朋友500块
    * */
    public boolean giveMoney(String Giver,String Revicer,int money)  {
        if(Giver==null||Revicer==null||money<0)
            return false;
        //连接数据库判断是否登陆成功
        //1.获取连接
        Connection conn= null;
        PreparedStatement pstmt1=null;
        PreparedStatement pstmt2=null;
        try {
            conn = JDBCUtil.getConnection();
            //开启事务
            conn.setAutoCommit(false);
            //2.定义sql
            String sql1="update login set money=money-? where name= ?";
            String sql2="update login set money=money+? where name= ?";
            //3.获取执行sql的对象
               pstmt1=conn.prepareStatement(sql1);
               pstmt2=conn.prepareStatement(sql2);
            //给?赋值
            pstmt1.setInt(1,500);
            pstmt1.setString(2,"大忽悠");
            pstmt2.setInt(1,500);
            pstmt2.setString(2,"小朋友");
            //4.执行
            pstmt1.executeUpdate();
            //异常的出现
            String s=null;
            s.getBytes(StandardCharsets.UTF_8);
            pstmt2.executeUpdate();
            //结束事务
            conn.commit();
            return true;
        } catch (SQLException throwables) {
            //事务进行回滚
            try {
                if(conn!=null)
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }finally {
            //父类指针指向子类引用
            JDBCUtil.close(pstmt1,conn);
            JDBCUtil.close(pstmt2,conn);
        }
        return false;
    }
}

在这里插入图片描述
开启事务后,一旦出现异常,可以通过事务回滚来恢复被修改的数据


数据库连接池

概念:

在这里插入图片描述


连接池实现

在这里插入图片描述


c3p0连接池

在这里插入图片描述

jar包的导入这里就不再多说了

这里配置文件中还需要对一些数据进行修改
在这里插入图片描述

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/test1</property>
    <property name="user">root</property>
    <property name="password">126433</property>
    
    <!-- 连接池参数 -->
    <!-- 初始化申请的连接数量 -->
    <property name="initialPoolSize">5</property>
    <!-- 最大的连接数量 -->
    <property name="maxPoolSize">10</property>
    <!-- 超时时间 -->
    <property name="checkoutTimeout">3000</property>
  </default-config>

  <named-config name="otherc3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">8</property>
    <property name="checkoutTimeout">1000</property>
  </named-config>
</c3p0-config>

主类连接测试:

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;


public class main {
    public static void main(String[] args) throws SQLException {
            //1.创建数据库连接池对象
        DataSource ds=new ComboPooledDataSource();
        //2.获取连接对象
        Connection conn=ds.getConnection();
        //3.打印
        System.out.println(conn);
    }
}

在这里插入图片描述

获取DataSource,使用指定名称配置,如果不传入字符串,指定默认第一个配置

在这里插入图片描述

public class main {
    public static void main(String[] args) throws SQLException {
            //1.获取DataSource,使用指定名称配置
        DataSource ds=new ComboPooledDataSource("dhy");
        //2.获取连接对象
        Connection conn=ds.getConnection();
        //3.打印
        System.out.println(conn);
    }
}

在这里插入图片描述
同时使用多个连接和归还连接

这里原本最多只能有8个连接,我们使用了9次连接,因为其中当i=3时,我们归还了一个连接,不然会报错

public class main {
    public static void main(String[] args) throws SQLException {
            //1.获取DataSource,使用指定名称配置
        DataSource ds=new ComboPooledDataSource("dhy");
        //2.获取连接对象
        for(int i=0;i<9;i++)
        {
            Connection conn=ds.getConnection();
            System.out.println(i+":"+conn);
            if(i==3)//归还连接到连接池
                conn.close();
        }
  

在这里插入图片描述


Druid连接池

在这里插入图片描述

配置文件:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test1
username=root
password=126433
#初始化连接数量
initialSize=5
#最大连接数
maxActive=10
#最大等待时间
maxWait=3000

连接代码演示:

public class main {
    public static void main(String[] args) throws Exception {
           //加载配置文件
        Properties pro=new Properties();
        InputStream is=main.class.getClassLoader().getResourceAsStream("druid.properties");
        pro.load(is);
        //获取连接池对象
        DataSource ds=DruidDataSourceFactory.createDataSource(pro);

        //获取连接
        Connection conn=ds.getConnection();
        System.out.println(conn);
    }
}

在这里插入图片描述


工具类

在这里插入图片描述

工具类完整代码:

package Utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtils {
      //1.定义成员变量
    private static DataSource ds;

    static {
        try {
            //1.加载配置文件
            Properties pro=new Properties();
            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            //2.获取DataSource
            ds= DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
    //释放资源
    public static void close(ResultSet res,Statement stmt, Connection conn)
    {
        if(res!=null)
        {
            try {
                res.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

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

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

    }

    public static void close(Statement stmt, Connection conn)
    {
         close(null,stmt,conn);
    }

    public static  DataSource getDataSource()
    {
        return ds;
    }

}


使用新的工具类进行测试:

package Utils;

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

public class testDemo1 {
    public static void main(String[] args)
    {
        Connection conn=null;
        PreparedStatement pstmt=null;
        try
        {
            //1.获取连接
            conn=JDBCUtils.getConnection();
            //2.定义sql
            String sql="insert into depart values(?,?)";
            //3.获取pstmt对象
            pstmt=conn.prepareStatement(sql);
            //4.给?赋值
            pstmt.setInt(1,520);
            pstmt.setString(2,"大忽悠和小朋友婚姻办");
            //5.执行sql语句
            int count=pstmt.executeUpdate();
            System.out.println("影响语句条数:"+count);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //释放资源
            JDBCUtils.close(pstmt,conn);
        }
    }
}

在这里插入图片描述
在这里插入图片描述


JDBC数据的批处理操作

默认情况下mysql的批处理没有开启,我们需要在url后面拼接一个参数即可

在这里插入图片描述
所要拼接的参数:

rewriteBatchedStatements=true

演示:

package Utils;

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

public class testDemo1 {
    public static void main(String[] args)
    {
        //记录耗费的时间
        long begin=System.currentTimeMillis();
        Connection conn=null;
        PreparedStatement pstmt=null;
        try
        {
            //1.获取连接
            conn=JDBCUtils.getConnection();
            //开启事务
            conn.setAutoCommit(false);
            //2.定义sql
            String sql="insert into boy values(null,?)";
            //3.获取pstmt对象
            pstmt=conn.prepareStatement(sql);
            //4.给?赋值
            for(int i=1;i<=10000;i++)
            {
                pstmt.setString(1,"小朋友"+i+"号");
                //添加到批处理
                pstmt.addBatch();
                //注意问题: 批处理里面写的sql语句,会被先放到内存中
                //为了防止内存溢出,我们可以等到批处理攒到1000条语句的时候,执行一次批处理
                //然后清空批处理
                if(i%500==0)
                {
                    //执行批处理
                    pstmt.executeBatch();
                    //执行完后内容还在内存上,我们还需要清空批处理
                    pstmt.clearBatch();
                }
            }
            // 将剩下的未处理命令发送给数据库
            pstmt.executeBatch();
            //手动提交事务
            conn.commit();
        } catch (SQLException throwables) {
            //事务进行回滚
            try {
                if(conn!=null)
                    conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }finally {
            //释放资源
            JDBCUtils.close(pstmt,conn);
        }
        long end=System.currentTimeMillis();
        System.out.println("插入一万条记录耗费的时间为:"+(end-begin));
    }
}

在这里插入图片描述
因为prepareStatement会对sql语句进行预编译,因此在执行样式类似的sql语句时,会很大优势,不需要对每一天sql都进行编译


Spring的Template

在这里插入图片描述

在这里插入图片描述

执行DML语句

修改表记录演示:


```java
package Utils;

import org.springframework.jdbc.core.JdbcTemplate;

public class testDemo1 {
    public static void main(String[] args)
    {
           //创建JDBCTemplate对象-----------需要一个DataSource对象
        JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());
        //调用方法
        String sql="UPDATE depart SET `name`='大忽悠和小朋友会计部' WHERE wID= ?";
        //返回影响的行数
        int count=template.update(sql,102);//这里如果有多个?,那么传入的参数顺序和?一一对应
        System.out.println("影响的行数:"+count);
    }
}

在这里插入图片描述

添加记录演示:

public class testDemo2 {
    JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());
    //junit单元测试,让方法能够独立运行
    @Test
    public void test()
            {
                //插入一条记录

                //1.获取datasource对象
                String sql="insert into boy(name) values(?)";
                int count=template.update(sql,"大忽悠");
                System.out.println(count);
            }
}

在这里插入图片描述

删除记录演示:

public class testDemo2 {
    JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());
    //junit单元测试,让方法能够独立运行
    @Test
    public void test()
            {
                //插入一条记录

                //1.获取datasource对象
                String sql="delete from boy where name= ?";
                int count=template.update(sql,"大忽悠");
                System.out.println(count);
            }
}

在这里插入图片描述


执行DQL语句

在这里插入图片描述

查询dno为3的员工记录:

        //创建JDBCTemplate对象-----------需要一个DataSource对象
        JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());

        String sql="select * from employee where dno= ?";
          //将查询结果封装为map集合
        Map<String,Object> map=template.queryForMap(sql,3);
        System.out.println(map);

在这里插入图片描述
在这里插入图片描述
说明这个方法查询的结果集长度只能是1

因为键值不能重复,而查询到的数据的列名被封装为了键值,这样在查询多条记录时,键值必定重复

JDBC从零开始的保姆级教程!!!插图58

查询dno=2的记录,将其封装为list集合:

可以用来查询多条记录,原理是将每一条记录都封装为一个map集合,最后将map装载到list里面

        //创建JDBCTemplate对象-----------需要一个DataSource对象
        JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());

        String sql="select * from employee where dno= ?";
          //将查询结果封装为map集合
        List<Map<String, Object>> map=template.queryForList(sql,3);
        System.out.println(map);

在这里插入图片描述
查询所有记录,将其封装为Emp对象的Lsit集合:

class Emp{
    public int did;
    public String dname;

    @Override
    public String toString() {
        return "Emp{" +
                "did=" + did +
                ", dname='" + dname + '\'' +
                '}';
    }
}
public class testDemo1 {
    public static void main(String[] args)
    {
        //创建JDBCTemplate对象-----------需要一个DataSource对象
        JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());

        String sql="select * from dept";
              List<Emp> list=template.query(sql, new RowMapper<Emp>() {
                  //该方法每调用一次,就会封装一个Emp对象然后返回
                  @Override
                  public Emp mapRow(ResultSet resultSet, int i) throws SQLException {
                         Emp emp=new Emp();
                         emp.did=resultSet.getInt("did");
                         emp.dname=resultSet.getString("dname");
                         return emp;
                  }
              });
       for(Emp emp:list)
           System.out.println(emp);
    }
}

在这里插入图片描述
简化----查询所有记录,使用BeanPropertyRowMapper对象

class Emp{
    public Integer money;//基本类型不接受赋值为null,要注意
    public String name;

    public Integer getMoney() {
        return money;
    }

    public String getName() {
        return name;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }

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

    @Override
    public String toString() {
        return "Emp{" +
                "money=" + money +
                ", name='" + name + '\'' +
                '}';
    }
}
public class testDemo1 {
    public static void main(String[] args)
    {
        //创建JDBCTemplate对象-----------需要一个DataSource对象
        JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());
        String sql="select * from login";
        //传入一个Emp的字节码文件对象,用反射去比较属性字段名和数据库字段名是否匹配,如果匹配就会把值拿出来装到对应set和get方法里面
        List<Emp> list=template.query(sql,new BeanPropertyRowMapper<Emp>(Emp.class));
       for(Emp emp:list)
       {
           System.out.println(emp);
       }
    }
}

在这里插入图片描述

注意:

在这里插入图片描述
传入一个Emp的字节码文件对象,用反射去比较属性字段名和数据库字段名是否匹配,如果匹配就会把值拿出来装到对应set和get方法里面

查询总记录数量:

public class testDemo1 {
    public static void main(String[] args)
    {
        //创建JDBCTemplate对象-----------需要一个DataSource对象
        JdbcTemplate  template=new JdbcTemplate(JDBCUtils.getDataSource());
        //查询总数,这里最后传入主键,提供效率
        String sql="select count(did) from dept";
        //返回一个long类型的值
          Long total=template.queryForObject(sql,long.class);
        System.out.println(total);
    }
}

在这里插入图片描述

赞(0) 打赏
未经允许不得转载:IDEA激活码 » JDBC从零开始的保姆级教程!!!

相关推荐

  • 暂无文章

一个分享Java & Python知识的社区