java-day13 JDBC

JDBC

概念:

JDBC(java data base connectivity)Java数据库连接,是一种用于执行sql语句的java的API

它是由使用java语言编写的类和接口组成。

本质上是sun公司定义的一套操作所有关系型数据库的规则,将来每个数据库厂商去写实现类实现接口,提供数据库jar包,程序员可以使用提供的jar包进行编程

JDBC快速实现

package com.company;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBC_Demo {
    public static void main(String[] args)  {
        //1.导入jar包:复制到src目录,右击选择 ---add as library
        //2。记载(注册)驱动

        //将来要抛出直接选中要抛出的全部代码块,ctrl+alt+t选择try+catch+finally


        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");//抛出异常


            //3,通过注册的驱动,获取数据库连接  Connection 是java.util下的

            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/zte",
                    "root","123456");

            //4.定义sql语句
            String sql="update  emp set sal=5000 where ename='张三'";
            String sql2="insert into emp values('10007','jack','clerk','2021-01-01','6000')";
            String sql3="delete from emp where empno='10007'";


            //5.获取到数据库连接

            stmt = conn.createStatement();

            //6.通过stmt对象,调用方法执行sql
            //如果执行成功,那么就会返回一个值,表示执行的行数值


            int i = stmt.executeUpdate(sql);
            int m= stmt.executeUpdate(sql2);
            int n= stmt.executeUpdate(sql3);


            //7.处理结果
            System.out.println(i >0 ? "i执行成功":"i执行失败");
            System.out.println(m >0 ? "m执行成功":"m执行失败");
            System.out.println(n >0 ? "m执行成功":"m执行失败");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //8.关闭资源
            try {
                stmt.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }



    }
}

数据库连接:mysql&oracle版本

jdbc:mysql://localhost:3306/数据库名?serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&characterEncoding=utf-8

oracle.jdbc.OracleDriver
jdbc:oracle:thin:@//192.168.100.160:1521/helowin

连接oracle数据库

package com.company;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBC_Oracle {
    public static void main(String[] args)  {
        //1.导入jar包:复制到src目录,右击选择 ---add as library
        //2。记载(注册)驱动
        Connection conn = null;
        Statement stmt=null;

        try {
            Class.forName("oracle.jdbc.OracleDriver");//抛出异常
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //3,通过注册的驱动,获取数据库连接  Connection 是java.util下的
        try {
            conn = DriverManager.getConnection("jdbc:oracle:thin:@//192.168.60.100:1521/orcl",
                   "scott","123456");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //4.定义sql语句
        String sql="update  emp set sal=5000 where empno=7499";

        //5.获取到数据库连接
        try {
            stmt = conn.createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //6.通过stmt对象,调用方法执行sql
        //如果执行成功,那么就会返回一个值,表示执行的行数值
        int i= 0;
        try {
            i = stmt.executeUpdate(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        //7.处理结果
        System.out.println(i >0 ? "i执行成功":"i执行失败");

        //8.关闭资源
        try {
            stmt.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }


    }
}

JDBC实现查询(mysql版本)

创建的同名实体类:

package com.company;

import java.util.Date;

/*实体类:把数据查询到的数据存放到实体类对象里,返回给前端
* 保证实体类的属性名称和类型与数据库表一致*/
public class Emp {
    private  int empno;
    private String ename;
    private String job;
    private Date hiredate;
    private double sal;


    //构造方法:全参加无参


    public Emp() {

    }

    public Emp(int empno, String ename, String job, Date hiredate, double sal) {
        this.empno = empno;
        this.ename = ename;
        this.job = job;
        this.hiredate = hiredate;
        this.sal = sal;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", hiredate=" + hiredate +
                ", sal=" + sal +
                '}';
    }

    public int getEmpno() {
        return empno;
    }

    public void setEmpno(int empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }


}

创建与表名同名实体类,通过创建集合来存放赋值后的实体类

package com.company;

import java.sql.*;

public class JDBCDemo02 {
    public static void main(String[] args)  {
        Connection connection= null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zte",
                   "root","123456");
            //conn获取statement
            statement = connection.createStatement();
            //执行查询
            //定义sql
            String sql="select * from emp";

            //获取结果集
            resultSet = statement.executeQuery(sql);
            //获取rs中的数据
            while (resultSet.next()){
                //表示获取数据库中第一列,数据类型是int类型的字段  括号里可以写字段所在行数或者直接输入字段名称
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                String job = resultSet.getString(3);
                String hiredate = resultSet.getString("hiredate");
                String sal = resultSet.getString("sal");

                System.out.println(id+" "+name+" "+job+" "+hiredate+" "+sal);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (resultSet !=null){
                    resultSet.close();
                }
                if (statement !=null){
                    statement.close();
                }
                if (connection !=null){
                    connection.close();
                }

            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
            }

        }




    }
}

JDBC中使用的对象总结:
DriverManager :驱动管理对象


功能:
1,注册驱动,告诉程序使用哪个数据库驱动jar包,mysql5版本之后,可以省略这一步2,获取数据库连接Connection:
static Connection getConnection(String url, String user, String password)尝试建立与给定数据库URL的连接。
参数:url表示连接数据库的地址
mysql地址: jdbc:mysql://主机ip:3306/数据库名
oracle地址: jdbc:oracle:thin:@//主机ip:1521/数据库名user表示连接数据库的用户名
password表示连接数据库的密码
 

Connection:数据库连接对象

功能︰
1,获取执行sql语句的对象
Statement createStatement()
创建一个Statement对象,用于将SQL语句发送到数据库。PreparedStatement prepareStatement(String sql)
创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。2,管理事务
void setAutoCommit(boolean autoCommit)将此连接的自动提交模式设置为给定状态。

void commit()使自上次提交/回滚以来所做的所有更改
void rollback()撤消在当前事务中所做的所有更改

Statement :执行sql对象

功能:

1,执行sql语句

ResultSet executeQuery(String sql)执行给定的SQL语句,该语句返回单个ResultSet对象。
int executeUpdate(String sql)执行给定的SQL语句,这可能是INSERT,UPDATE,或DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。
ResultSet :查询返回的结果集对象,封装查询结果的
ResultSet对象保持一个光标指向其当前的数据行。
最初,光标位于第一行之前。next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false,因此可以在while循环中使用循环来遍历结果集。

常用方法:
1, boolean next()将光标从当前位置向前移动一行。2,getXxx(参数)方法︰获取结果集中具体值的方法
方法名Xxx:获取到的数据类型是什么类型,这里的Xxx就用什么类型
比如,字段是int类型的,那么就用getlnt(),字段是字符串类型,就用getString()字段是小数类型,就用getDouble()
参数︰参数可以传入两个类型,一个int,一个String
int代表传入的是获取第几列的数据
String代表传入获取指定的字段名的数据,如果字段名是sname,类型String方法的写法: getString("sname")
PreparedStatement :处理预编译的SQL

SQL注入问题∶

使用PrepareStatement解决sql注入问题


编写SQL语句的时候,使用字符串拼接的方式,拼接数据,会产生的一些问题
为了避免这个问题,JDBC中提供了PreparedStatement对象,可以通过处理预编译SQL的方式,完成SQL的查询
用法︰
1,定义sql的时候,将需要传入的参数,使用?代替,
比如SELECT* FROM USER WHERE NAME = ? AND pwd = ?
2,conn对象调用方法,传入sql语句,进行预编译处理,并返回pstmt对象3,通过pstmt对象,完成?(占位符)的赋值,调用setXxx(参数)方法
set方法的名称类型和你要赋值的实际字段类型─致
参数:第一个参数表示给第几个?赋值,第二个参数表示具体的值4,通过pstmt对象,调用方法,执行sql
executeQuery()执行查询executeUpdate()执行增删改
 

使用java+jdbc完成简单的用户登录功能

package com.company;

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

public class JDBCLoginDemo {
    public static void main(String[] args)  {


        //模拟用户登录功能
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名");
        String username = scanner.nextLine();
        System.out.println("请输入密码");
        String userpassword=scanner.nextLine();

        Connection connection= null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zte",
                    "root","123456");
            //conn获取statement
            statement = connection.createStatement();
            //执行查询
            //定义sql
            String selectuser = "select * from user where name ='"+ username+"' and pwd = '"+userpassword+"'";


            //获取结果集
            resultSet = statement.executeQuery(selectuser);
            if (resultSet.next()){
                System.out.println("用户存在,登录成功");
            }else {
                System.out.println("用户不存在,登录失败");
            }


        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (resultSet !=null){
                    resultSet.close();
                }
                if (statement !=null){
                    statement.close();
                }
                if (connection !=null){
                    connection.close();
                }

            } catch (SQLException e) {
                e.printStackTrace();
            } 

        }


    }


}

statement只能支持字符串拼接,因此可能会出现SQL注入问题

为此,提供了preparestatement来解决问题

使用PrePareStatement优化版

package com.company;

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

public class PrepareSteateDemo {
    public static void main(String[] args)  {


        //模拟用户登录功能
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名");
        String username = scanner.nextLine();
        System.out.println("请输入密码");
        String userpassword=scanner.nextLine();

        Connection connection= null;

        PreparedStatement pstmt=null;
        ResultSet resultSet = null;
        try {
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zte",
                    "root","123456");


            //执行查询
            //定义sql
            String selectuser = "select * from user where name = ? and pwd = ? ";
            pstmt=connection.prepareStatement(selectuser);
            //conn获取pstmt对象
            pstmt.setString(1,username);
            pstmt.setString(2,userpassword);

            //获取结果集
            resultSet = pstmt.executeQuery();

            if (resultSet.next()){
                System.out.println("用户存在,登录成功");
            }else {
                System.out.println("用户不存在,登录失败");
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (resultSet !=null){
                    resultSet.close();
                }
                if (pstmt !=null){
                    pstmt.close();
                }
                if (connection !=null){
                    connection.close();
                }

            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
        
    }


}

将来在日常开发中都不再使用Statement而使用PrepareStatement

executeQuery()方法:执行查询,括号里放定义的sql语句

executeUpdate()方法:执行增删改

JDBC事务

通过转账案例模拟事务的处理流程

一次转账中,包含两次修改操作,如果这两次操作之中发生了异常,应该对事务进行回滚,否则数据的一致性不能得到保证。

package com.company;

import java.sql.*;

public class JDBCComment {
    public static void main(String[] args)  {
        try {
            Connection coon= JDBCUtil.getConnection();
            coon.setAutoCommit(false);//手动打开事务

            String sql1="update tb_account set money =money-? where name=?";
            PreparedStatement srpst =coon.prepareStatement(sql1);
            srpst.setInt(1,200);
            srpst.setString(2,"zhangsan");
            int i=srpst.executeUpdate();
            int m=1;
            int a=3/m;//模拟一个异常
            //操作事务2
            String sql2="update tb_account set money =money+? where name=?";
            PreparedStatement srpst2 =coon.prepareStatement(sql2);
            srpst2.setInt(1,200);
            srpst2.setString(2,"lisi");

            int j=srpst2.executeUpdate();
            //提交事务
            coon.setAutoCommit(true);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {

        }


    }
}

编写JDBC工具类


工具类主要是为了简化书写,将共同的内容抽取到方法中使用需要抽取哪些?
1,注册驱动
2,获取数据库连接方法
解决问题:不想每次调用都去传递参数,还得保证工具类的通用性3,关闭资源方法
 

JDBCUtil工具类

package com.company;

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

public class JDBCUtil {
    //想办法可以让变量值动态的进行获取,可以根据用户的需求自定义传入url,user,password
    //而且传入之后,让数据能获取,并且加载

   private static String url;
   private static String username;
   private static String password;
   private static String driver;

    static{
        try {
        InputStream is=JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();

            properties.load(is);
            //获取到配置文件中的数据
            url =properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            driver = properties.getProperty("driver");
            Class.forName(driver);

        } catch (IOException|ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //获取连接方法
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);

    }
    //获取pstmt对象的方法封装
    public static PreparedStatement getPstmt(String sql,Connection conn) throws SQLException {
        return conn.prepareStatement(sql);


    }

    //关闭方法
    public static  void close(ResultSet rs, Statement stmt, Connection conn){
        try {
            if (rs !=null){
                rs.close();
            }
            if (stmt !=null){
                stmt.close();
            }
            if (conn !=null){
                conn.close();
            }


        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

配置文件

//jdbc.properties配置文件
url=jdbc:mysql://localhost:3306/zte?serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
driver=com.mysql.jdbc.Driver

数据库连接池

为什么需要数据库连接池?

因为频繁的获取Connection对象,需要消耗很多的资源,所以可以利用池子技术,在连接池中放好创建好的Connection对象,下次使用,直接从池子中获取,用完之后调用close()方法,将对象再还到池子里。

package com.company.JDBCpool;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;

/*数据库连接池需要实现一个官方提供的接口:DataSorce*/
public class JDBCPool implements DataSource {

    //创建连接池
    private static LinkedList<Connection> list= new LinkedList<>();
    //希望类在加载的时候就在连接池中放满Connection对象(设置静态代码块)

    static{
        try {

        InputStream is=  JDBCPool.class.getClassLoader().getResourceAsStream("jdbc.properties");
    //创建properties,并加载输入流
        Properties properties=new Properties();

            properties.load(is);
            String url= properties.getProperty("url");
            String username=properties.getProperty("username");
            String password =properties.getProperty("password");
            String driver =properties.getProperty("driver");

            //注册驱动
            Class.forName(driver);
            for (int i = 0; i < 10; i++) {
                Connection conn = DriverManager.getConnection(url,username,password);
           list.add(conn);
            }
        } catch (IOException | ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }



    @Override
    public Connection getConnection() throws SQLException {
        System.out.println("当前的池子中,还有:" + list.size() +"个conn对象");
        Connection conn = list.removeFirst();
        System.out.println("conn对象被取走一个,当前的池子中,还有:"+list.size() +"个conn对象");
        //让Proxy动态代理connection对象,判断connection将来执行的方法
        return (Connection) Proxy.newProxyInstance(JDBCPool.class.getClassLoader(),
                conn.getClass().getInterfaces(),
                new InvocationHandler() {
                    //将来当connection执行方法的时候,都会经过这个invoke方法
                    // 只需要判断使用的是否是close方法,如果close,就做单独处理
                    // 如果是其他方法,正常执行
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("close")){
                            //将conn对象还到池子里
                            list.add(conn);
                            System.out.println("池子中归还了一个conn对象,现在大小是:"+ list.size());

                        } else {
                            //其他情况继续执行方法
                            method.invoke(conn, args);
                        }
                        return null;
                    }
                });

    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}

数据库连接池测试类

package com.company.JDBCpool;

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

public class JDBCTest {
    public static void main(String[] args) throws SQLException {

        JDBCPool Pool = new JDBCPool();
        Pool.getConnection();//剩9
        Pool.getConnection();//剩8
        Pool.getConnection();//剩7
        //这个conn获取后,就归还
        Connection conn = Pool.getConnection();//剩6
        conn.close();//剩7

        Pool.getConnection();//剩6

    }
}

运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值