Jdbc

2019-08-20  本文已影响0人  小心草丛

Jdbc核心

1、Jdbc介绍

1>什么是jdbc
Java Database Connectivity
使用Java代码访问数据库的一种技术解决方案,Jdbc中定义了一套标准接口,即访问数据库的通用API,不同的数据库厂商必须去实现这些接口,以此可以通过相同的方式来访问不同的数据库,实现与具体数据库无关的Java操作

image.png

2>jdbc的工作原理
1)Jdbc技术标准定义一系列接口
在接口中定义访问数据库以及对数据表进行操作的抽象方法
2)各大数据库厂商自己写接口的实现类
将接口的实现类封装成驱动包提供给程序开发人员使用
3)程序员导入驱动包,访问数据时调用JDBC定义的接口
根据多态,实际底层调用的是数据库厂商的实现类

image.png

2、Jdbc增删改查使用步骤

package com.lanou.jdbc;

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

/**
 * Jdbc访问数据基本操作演示,
 * 查询lanou库下myemp表中的所有数据
 */
public class JdbcDemo01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1、加载驱动程序到内存中
        Class.forName("com.mysql.jdbc.Driver");

        //2、创建与数据库之间的连接(url,username,password)
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/lanou", "root","1234");
        System.out.println(conn);

        //3、构建给数据库发送sql语句的对象
        Statement stmt = conn.createStatement();

        //4、发送sql语句,并将查询接口封装到ResultSet中
        ResultSet rs = stmt.executeQuery("select * from myemp");

        //5、处理结果集
        // 结果集行指针,默认指向第一行上面
        //next() 判断有没有下一行,有自动挪到下一行,并取该行数据
        while(rs.next()) {
            //通过指定列名,获取该列下数据
            int id = rs.getInt("id");
            String name = rs.getString("name");
            double salary = rs.getDouble("salary");
            Date hiredate = rs.getDate("hiredate");
            //System.out.println(id+" "+name+" "+salary+" "+hiredate);

            //通过指定列顺序来获取列下面的值(列顺序从1开始)
            id = rs.getInt(1);
            name = rs.getString(2);
            salary = rs.getDouble(5);
            hiredate = rs.getDate(6);
            System.out.println(id+":"+name+":"+salary+":"+hiredate);
        }
        //6、关闭资源(后打开的先关闭)
        if(rs!=null){
            rs.close();
        }
        if(stmt!=null){
            stmt.close();
        }
        if(conn!=null){
            conn.close();
        }
    }
}
package com.lanou.jdbc;

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

/**
 * Jdbc访问数据基本操作演示,
 * 对lanou库下dept表的增删改操作
 */
public class JdbcDemo02 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        while(true){
            System.out.println("请输入指令:1>插入,2>删除,3>修改");
            int type = new Scanner(System.in).nextInt();
            switch (type) {
            case 1:
                add();
                break;
            case 2:
                delete();//根据部门编号删除
                break;
            case 3:
                update();//根据部门编号修改
                break;
            }
        }
    }
    
    /**插入数据*/
    public static void add() throws ClassNotFoundException, SQLException{
        System.out.println("输入部门编号:");
        int deptno = new Scanner(System.in).nextInt();
        System.out.println("输入部门名称:");
        String dname = new Scanner(System.in).nextLine();
        System.out.println("输入部门地址:");
        String location = new Scanner(System.in).nextLine();
        
        //sql语句换行注意空格
        String sql = "INSERT INTO dept "
                + "VALUES("+deptno+",'"+dname+"','"+location+"')";
        System.out.println(sql);
        executeSql(sql);
    }
    /**修改数据*/
    public static void update() throws ClassNotFoundException, SQLException{
        System.out.println("输入要修改的部门编号:");
        int deptno = new Scanner(System.in).nextInt();
        System.out.println("输入要修改的部门名称:");
        String dname = new Scanner(System.in).nextLine();
        System.out.println("输入要修改的部门地址:");
        String location = new Scanner(System.in).nextLine();
        
        //修改的sql
        String sql = "update dept set dname='"+dname+"',"
                + "location='"+location+"' where deptno="+deptno;
        System.out.println(sql);
        executeSql(sql);
    }
    
    /**删除数据
     * @throws Exception */
    private static void delete()  throws ClassNotFoundException, SQLException {
        System.out.println("输入要删除的部门编号:");
        int deptno = new Scanner(System.in).nextInt();
        //删除sql
        String sql = "delete from dept where deptno="+deptno;
        System.out.println(sql);
        executeSql(sql);
    }
    
    /**用于执行增删改sql语句的方法*/
    public static void executeSql(String sql) throws ClassNotFoundException, SQLException {
        //1、加载驱动程序到内存中
        Class.forName("com.mysql.jdbc.Driver");

        //2、创建与数据库之间的连接(url,username,password)
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/lanou", "root","1234");
        System.out.println(conn);

        //3、构建给数据库发送sql语句的对象
        Statement stmt = conn.createStatement();
        
        //4、执行语句,返回受影响行数
        int rows = stmt.executeUpdate(sql);
        if(rows!=0) {
            System.out.println("数据操作成功");
        }
    }
}

3、Jdbc中核心API

主要API:(JDBC定义的接口标准)

4、SQL注入演示

所谓SQL注入,就是通过把SQL命令插入到Web[表单]提交或输入域名或请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句

1、创建一张user表如下


image.png

2、代码

package com.lanou.jdbc;

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

/**
 * SQL注入演示
 */
public class JdbcDemo03 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1、加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2、创建连接
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/lanou",
                "root","1234");
        //3、创建Statement
        Statement stmt = conn.createStatement();
        //4、执行sql语句
        //登录:根据账号和密码查询信息
        System.out.println("===用户登录===");
        System.out.println("请输入账号:");
        String username = new Scanner(System.in).nextLine();
        System.out.println("请输入密码:");
        String password = new Scanner(System.in).nextLine();
        
        //这里可以通过拼接字符串的方式来造成sql注入
        String sql = "select * from user "
                + "where username='"+username+"' and password='"+password+"'";
        System.out.println(sql);
        //5、执行sql
        ResultSet rs = stmt.executeQuery(sql);
        if(rs.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        //6、释放资源
        if(rs!=null){
            rs.close();
        }
        if(stmt!=null){
            stmt.close();
        }
        if(conn!=null){
            conn.close();
        }
    }
}

5、PreparedStatement应用

package com.lanou.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

public class JdbcDemo04 {
    public static void main(String[] args) throws Exception {
        System.out.println("请输入指令:1>登录2>注册");
        int type = new Scanner(System.in).nextInt();
        switch (type) {
        case 1:
            login();
            break;
        case 2:
            regist();
        }
    }
    
    /**用户登录*/
    public static void login() throws ClassNotFoundException, SQLException {
        //1、加载驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2、创建连接
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/lanou1811",
                "root","1234");

        //3、预编译sql语句
        //   ?充当占位符
        String sql = "select * from user "
                + "where username=? and password=?";
        //会将sql语句发送给数据库,但不会立即执行
        PreparedStatement pstmt = 
                conn.prepareStatement(sql);
        //给占位符赋值,sql语句从左到右,从1开始
        System.out.println("===用户登录===");
        System.out.println("请输入账号:");
        String username = new Scanner(System.in).nextLine();
        System.out.println("请输入密码:");
        String password = new Scanner(System.in).nextLine();
        pstmt.setString(1,username);
        pstmt.setString(2,password);
        System.out.println(sql);

        //4、执行sql语句
        ResultSet rs = pstmt.executeQuery();
        if(rs.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }

        //5、释放资源
        if(rs!=null){
            rs.close();
        }
        if(pstmt!=null){
            pstmt.close();
        }
        if(conn!=null){
            pstmt.close();
        }
    }
    
    /**用户注入*/
    private static void regist() throws Exception{
        //1、加载驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2、创建连接
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/lanou1811",
                "root","1234");

        //3、预编译sql语句
        System.out.println("===用户注册===");
        //判断账号是否和已有账号重复,如果重复了重新输入
        //判断用户名是否存在
        boolean isUserNameExists = true;
        String username;

        do{
            System.out.println("请输入账号:");
            username = new Scanner(System.in).nextLine();
            //判断账号是否为空
            if("".equals(username)||username==null){
                System.out.println("账号不能为空");
                continue;
            }
            String sql = "select * from user where "
                    + " username=?";
            PreparedStatement pstmt = 
                    conn.prepareStatement(sql);
            pstmt.setString(1,username);
            //执行sql
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()){//账号已存在
                isUserNameExists = true;
                System.out.println("账号已存在,请重新输入");
            }else{//账号不存在
                isUserNameExists = false;
                System.out.println("恭喜,账号可以使用");
            }
        }while(isUserNameExists);

        //判断密码是否为空
        boolean isPwdNull = false;
        String password = null;
        do{
            System.out.println("请输入密码:");
            password = new Scanner(System.in).nextLine();
            if("".equals(password)||password==null){
                System.out.println("密码不能为空,重新输入");
                isPwdNull = true;
            }else{
                isPwdNull = false;
            }
        }while(isPwdNull);
        
        //预编译插入的sql语句
        String sql = "insert into user(username,password)"
                + " values(?,?)";
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setString(1,username);
        pstmt.setString(2,password);

        //4、执行sql语句,返回受影响的行数
        int rows = pstmt.executeUpdate();
        if(rows!=0){
            System.out.println("数据插入成功");
        }else{
            System.out.println("数据插入失败");
        }

        //5、释放资源
        if(pstmt!=null){
            pstmt.close();
        }
        if(conn!=null){
            pstmt.close();
        }
    }
}

6、Jdbc通用封装

1>配置文件
properties配置文件,便于修改

#jdbc.properties文件配置
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/lanou1811
jdbc.username=root
jdbc.password=1234
empDao=jdbc.EmpDaoImpl
#deptDao=jdbc.DeptDaoImpl

2>读取并加载配置信息

/**
 * 读取properties配置文件
 */
public class Config{
    static Properties pro = new Properties();
    static{
        loadPro();
    }
    public static void loadPro(){
        //从类路径下加载配置文件
        InputStream in = Config.class.getClassLoader().
            getResourceAsStream("jdbc.properties");
        try {
            pro.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    /**
     * 根据key获取value值
     * @param key
     * @return
     */
    public String getValue(String key){
        return pro.getProperty(key);
    }
}
/**存储全局常量*/
public class GlobalConst {
    static Config config = new Config();
    
    //url
    public static final String URL = 
            config.getValue("url");
    //driver
    public static final String DRIVER = 
            config.getValue("driverClassName");
    //username
    public static final String USERNAME = 
            config.getValue("username");
    //password
    public static final String PASSWORD = 
            config.getValue("password");
    
}

3>jdbc工具类
主要封装connection连接对象的获取和关闭操作
通过ThreadLocal保证一个线程一个连接对象

/**工具类*/
public class JdbcUtil extends GlobalConst{
    /**
     * 封装获取连接的方法
     * @return
     * @throws ClassNotFoundException 
     * @throws SQLException 
     * 一个线程一个连接对象
     * 
     * ThreadLocal:可以将一个对象绑定到当前线程
     */
    static ThreadLocal<Connection> td = 
            new ThreadLocal<>();
    public static Connection getConnection() throws ClassNotFoundException, SQLException{
        //判断当前线程有没有绑定连接对象
        //如果有直接返回,
        //如果没有则创建一个连接对象并绑定到当前线程
        Connection conn = td.get();
        if(conn==null){
            //1、加载驱动
            Class.forName(DRIVER);
            //2、创建连接
            conn = DriverManager.getConnection(
                    URL,USERNAME,PASSWORD);
            //3、将连接对象绑定到当前线程
            td.set(conn);
        }
        return conn;
    }
    
    /**
     * 释放资源
     *     connection
     *     statement/preparedStatement
     *     resultset
     * */
    public static void release(Connection conn,
            Statement stmt,ResultSet rs){
        try {
            if(rs!=null)rs.close();
            if(stmt!=null)stmt.close();
            if(conn!=null){
                //将conn对象从当前线程移除
                td.remove();
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 对增删改三个方法封装
     * @param sql
     * @param parameter  给占位符参数
     * @return  DML操作受影响行数
     */
    public static int update(String sql,Object[] parameters){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JdbcUtil.getConnection();
            pstmt = conn.prepareStatement(sql);
            //给占位符赋值
            for(int i=0;i<parameters.length;i++){
                pstmt.setObject(i+1,parameters[i]);
            }
            return pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            JdbcUtil.release(conn,pstmt,null);
        }
        return 0;
    }
}

4>实体类
便于对数据库中数据的封装
ORM:Object Relation Mapping 描述对象和数据之间映射
将java程序中对象对应到数据库中表
-表和类的对应
-表中字段和类中属性对应
-记录和对象对应

package com.lanou.jdbc;

import java.io.Serializable;
import java.sql.Date;

/**
 * 数据库中每有一张表都应该对应java中一个实体类
 * 表的字段对应实体类的属性
 * 每一行记录对应实体类一个对象
 * ORM:Object Relation Mapping
 *       对象关系映射
 */
public class Emp implements Serializable{
    private int id;
    private String name;
    private String sex;
    private String job;
    private double salary;
    private Date hiredate;
    private int deptno;
    
    public Emp() {
        super();
    }
    public Emp(int id, String name, String sex, String job, double salary, Date hiredate, int deptno) {
        super();
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.job = job;
        this.salary = salary;
        this.hiredate = hiredate;
        this.deptno = deptno;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public Date getHiredate() {
        return hiredate;
    }
    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }
    public int getDeptno() {
        return deptno;
    }
    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }
    @Override
    public String toString() {
        return "Emp [id=" + id + ", name=" + name + ", sex=" + sex + ", job=" + job + ", salary=" + salary
                + ", hiredate=" + hiredate + ", deptno=" + deptno + "]";
    }
    
}

5>dao
Data Access Object 数据访问对象
数据访问对象,封装对数据库的访问操作
建立在业务层和数据库之间,封装所有对数据库的访问操作
目的:数据访问逻辑和业务逻辑分开

/**
 * DAO:Data Access Object
 *     数据访问对象
 *     该类专门用于封装访问数据库的操作
 *     降低程序与数据库之间的耦合度
 */
public interface EmpDao {
    /**查询所有数据*/
    public List<Emp> findAll();
    /**根据id查询某一条记录*/
    public Emp findEmpById(int id);
    /**根据id删除某一条记录*/
    public int deleteEmpById(int id);
    /**插入一条记录*/
    public int addEmp(Emp emp);
    /**修改一条记录*/
    public int updateEmp(Emp emp);
}
package com.lanou.jdbc;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


/**
 *EmpDao接口实现类
 */
public class EmpDaoImpl implements EmpDao{

    @Override
    public List<Emp> findAll() {
        List<Emp> emps = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtil.getConnection();
            String sql = "select * from myemp";
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();
            //将每一行记录封装成一个emp对象,然后存入list集合
            while(rs.next()){
                int id  = rs.getInt("id");
                String name = rs.getString("name");
                String sex = rs.getString("sex");
                String job = rs.getString("job");
                double salary = rs.getDouble("salary");
                Date hiredate = rs.getDate("hiredate");
                int deptno = rs.getInt("deptno");
                
                Emp emp = new Emp(
                    id, name, sex, job, salary, 
                    hiredate, deptno);
                emps.add(emp);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally{
            JdbcUtil.release(conn, pstmt, rs);
        }
        return emps;
    }

    @Override
    public Emp findEmpById(int id) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Emp emp = null;
        try {
            conn = JdbcUtil.getConnection();
            pstmt = conn.prepareStatement(
                "select * from myemp where id=?");
            pstmt.setInt(1,id);
            rs = pstmt.executeQuery();
            if(rs.next()){
                emp = new Emp();
                emp.setId(id);
                emp.setName(rs.getString("name"));
                emp.setSex(rs.getString("sex"));
                emp.setJob(rs.getString("job"));
                emp.setSalary(rs.getDouble("salary"));
                emp.setHiredate(rs.getDate("hiredate"));
                emp.setDeptno(rs.getInt("deptno"));
            }
        } catch (Exception e) {
        } finally {
            JdbcUtil.release(conn, pstmt, rs);
        }
        return emp;
    }
    /**
    *String[] array;
    *array = {1,2,3};
    *
    *array = new String[]{1,2,3}
     */
    @Override
    public int deleteEmpById(int id) {
        return update(
            "delete from myemp where id=?",
            new Object[]{id});
    }

    @Override
    public int addEmp(Emp emp) {
        return update(
                "insert into myemp(name,sex,job,"
                + "salary,hiredate,deptno)"
                + "values(?,?,?,?,?,?)",
                new Object[]{
                    emp.getName(),
                    emp.getSex(),
                    emp.getJob(),
                    emp.getSalary(),
                    emp.getHiredate(),
                    emp.getDeptno()
                });
    }

    @Override
    public int updateEmp(Emp emp) {
        return update(
                "update myemp set "
                + "name=?,"
                + "sex=?,"
                + "job=?,"
                + "salary=?,"
                + "hiredate=?,"
                + "deptno=?"
                + "where id=?",
                new Object[]{
                    emp.getName(),
                    emp.getSex(),
                    emp.getJob(),
                    emp.getSalary(),
                    emp.getHiredate(),
                    emp.getDeptno(),
                    emp.getId()
                });
    }
    
    /**
     * 对增删改三个方法封装
     * @param sql
     * @param parameter  给占位符参数
     * @return  DML操作受影响行数
     */
    public int update(String sql,Object[] parameters){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JdbcUtil.getConnection();
            pstmt = conn.prepareStatement(sql);
            //给占位符赋值
            for(int i=0;i<parameters.length;i++){
                pstmt.setObject(i+1,parameters[i]);
            }
            return pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            JdbcUtil.release(conn,pstmt,null);
        }
        return 0;
    }
    
}

6>工厂模式dao

package com.lanou.jdbc;
/**
 * 用于生产dao对象的工厂
 */
public class DaoFactory {
    /**
     * empDao  deptDao
     * @param daoName
     * @return 
     * @throws ClassNotFoundException 
         *使用反射封装
     */
    public static Class<?> getDao(String daoName) throws ClassNotFoundException{
        Config config = new Config();
        String daoClassName = config.getValue(daoName);
        //根据类的全限定名获取类对象
        Class<?> clz = Class.forName(daoClassName);
        return clz;
    }
    /**不用反射封装*/
    /*public static EmpDao getEmpDao(){
        return new EmpDaoImpl();
    }
    public static DeptDao getDeptDao(){
        return new DeptDaoImpl();
    }*/
}

7>测试

package com.lanou.jdbc;

import java.util.List;

/**测试jdbc封装*/
public class Test6 {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        //获取dao对象
        EmpDao dao = (EmpDao) DaoFactory.getDao("empDao").newInstance();
        
        List<Emp> emps = dao.findAll();
        for(Emp emp:emps){
            System.out.println(emp);
        }
        
//      Emp emp = dao.findEmpById(3);
//      System.out.println(emp);
    
//      int rows = dao.deleteEmpById(11);
//      System.out.println(rows);
    }
}

上一篇下一篇

猜你喜欢

热点阅读