JDBC操作

JDBC

1. JDBC背景

JDBC类似pymysql

JDBC,官方定义的操作所有关系型数据库的规则,(一套接口)
本质:
代替程序员操作数据库,使用java操作
数据库厂商自己写实现类
我们只需要调JDBC的接口就ok了
多态调用

使用步骤:

在导入数据包的过程中总是报错后来,通过 select version(); 查看mysql版块与jar版本不符合,在mysql官网下载对应版主之后继续运行.

		1. 导入驱动jar包 mysql-connector-java-8.25-bin.jar
			1.复制mysql-connector-java-8.25-bin.jar到项目的libs目录下
			2.右键-->Add As Library
		2. 注册驱动
		3. 获取数据库连接对象 Connection
		4. 定义sql
		5. 获取执行sql语句的对象 Statement
		6. 执行sql,接受返回结果
		7. 处理结果
		8. 释放资源

初识JDBC

public class Demo01JDBC {
    public static void main(String[] args) throws Exception {
        //1.导入驱动jar包
        //2.注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //JDK1.5版本之后现在不用注册驱动
        //3.获取数据库的连接对象
        //如果连接本机mysql服务器,并且服务器端口好是3306,则url可以简写,为jdbc:mysql:///python
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/python","root","123456");
        //4.定义sql语句
        String sql = "update classes set name = '三班' where id = '2';";
        //5.获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        //6.执行sql
        int count = stmt.executeUpdate(sql);
        //7.处理结果
        System.out.println(count);
        //8.释放资源
        stmt.close();
        conn.close();
    }
}
2. DriverManager:驱动管理对象
  • 功能:

    1. 注册驱动:告诉程序该使用哪一个数据库驱动jar
      static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。
      写代码使用: Class.forName(“com.mysql.jdbc.Driver”);
      通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
      static {
      try {
      java.sql.DriverManager.registerDriver(new Driver());
      } catch (SQLException E) {
      throw new RuntimeException(“Can’t register driver!”);
      }
      }

    注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。
    2. 获取数据库连接:

    • 方法:static Connection getConnection(String url, String user, String password)
    • 参数:
      • url:指定连接的路径
        • 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
        • 例子:jdbc:mysql://localhost:3306/db3
        • 细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称
      • user:用户名
      • password:密码
3. Connection:数据库连接对象
  1. 功能:
  2. 获取执行sql 的对象
* **Statement createStatement()**
* **PreparedStatement prepareStatement(String sql)**  
  1. 管理事务:
* 开启事务:**setAutoCommit(boolean autoCommit)** :调用该方法设置参数为false,即开启事务
* 提交事务:**commit()** 
* 回滚事务:**rollback()** 
4. Statement:执行sql的对象
  1. 执行sql
    1. boolean execute(String sql) :可以执行任意的sql 了解
    2. int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句 返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
    3. ResultSet executeQuery(String sql) :执行DQL(select)语句
5. ResultSet:结果集对象,封装查询结果

​ boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true

getXxx(参数):获取数据

​ Xxx:代表数据类型 如: int getInt() , String getString()

​ 参数:

​ int:代表列的编号,从1开始 如: getString(1)

​ String:代表列名称。 如: getDouble(“balance”)

代码实现

import java.sql.*;

public class Demo05JDBC {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //1.注册驱动
            //Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接对象
            conn = DriverManager.getConnection("jdbc:mysql:///python","root","123456");
            //3.定义sql
            String sql = "select * from classes";
            //4.获取执行sql对象
            stmt = conn.createStatement();
            //5.执行sql语句
            rs = stmt.executeQuery(sql);
            //6.处理结果
            //System.out.println(rs);
            //6.1让游标向下移动一行
            while (rs.next()) {
                int id = rs.getInt(1);
                String str = rs.getString(2);
                System.out.println(id+"---"+str);
            }
        }  catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //7.释放资源

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

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

输出结果:

1—三班
2—三班
4—三班

JDBC 工具类

此时我们发现在我们的代码当作,有非常多重复的代码,

比如

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

finally {
            //7.释放资源

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

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

那么我们可不可以给他写一个工具类,我们的目的呢是简化书写

在我们的工具类中肯定有这样的一个代码块用来关闭请求资源的。

public static void close(Statement stmt,Connection conn){
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

同时有的时候我们还会请求ResultSet的资源,在用到查询操作的时候

于是重载close方法

public static void close(ResultSet rs, Statement stmt, Connection conn){
    if( rs != null){
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

利用Java中的静态代码块,在类加载时会执行的特点

static {
    //读取资源文件,获取值
    try {
        //1.创建Properties集合类
        Properties pro = new Properties();
        //2.加载文件
        //获取src路径下的文件方式-->ClassLoader 类加载器
        ClassLoader classLoader = Demo02JDBCUtils.class.getClassLoader();
        URL res = classLoader.getResource("jdbc.properties");
        String path = res.getPath();
        pro.load(new FileReader("C:\\Users\\86157\\Desktop\\javatest\\java基础\\12JDBC\\jdbc.properties"));
        //4. 注册驱动
        //Class.forName(driver);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

这是上图中,URL res = classLoader.getResource(“jdbc.properties”);加载的配置文件

文件内容很容易理解,利用了Properties这个集合类来读取文件内容

url=jdbc:mysql:///python
user=root
password=123456
driver=com.mysql.jdbc.Driver

此时呢,pro读取了配置文件中的数据,通过get方法,将它赋值给我们设置的静态变量

url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");

对了,我们在static外面还要设置静态变量

//静态代码块,配置文件只需要读取一次
private static String url;
private static String user;
private static String password;
private static String driver;

此时我们在定义一个getConnection的方法,来获取Connection这个类,进而通过conn来获取执行sql的对象

public static Connection getConnection() throws SQLException {

    return DriverManager.getConnection(url, user, password);
}

现在我们的工具类基本上是完成了

整体写一下

package Demo02封装类;

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

/*
    简化书写
 */
public class Demo02JDBCUtils {
    //静态代码块,配置文件只需要读取一次
    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    static {
        //读取资源文件,获取值
        try {
            //1.创建Properties集合类
            Properties pro = new Properties();
            //2.加载文件
            //获取src路径下的文件方式-->ClassLoader 类加载器
            ClassLoader classLoader = Demo02JDBCUtils.class.getClassLoader();
            URL res = classLoader.getResource("jdbc.properties");
            String path = res.getPath();
            pro.load(new FileReader("C:\\Users\\86157\\Desktop\\javatest\\java基础\\12JDBC\\jdbc.properties"));
            //3.获取数据,赋值
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");
            //4. 注册驱动
            //Class.forName(driver);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {

        return DriverManager.getConnection(url, user, password);
    }


    public static void close(Statement stmt,Connection conn){
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
    public static void close(ResultSet rs, Statement stmt, Connection conn){
        if( rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

}

封装类

现在我们有一个需求,希望把数据库中的对象封装在java的类中,以便于后续来对他进行处理

JDBC操作

如图这是我们的商品

class goods{
    private int id;
    private String name;
    private String cate_name;
    private String brand_name;
    private int price;

    @Override
    public String toString() {
        return "goods{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", cate_name='" + cate_name + '\'' +
                ", brand_name='" + brand_name + '\'' +
                ", price=" + price +
                '}';
    }

    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 getCate_name() {
        return cate_name;
    }

    public void setCate_name(String cate_name) {
        this.cate_name = cate_name;
    }

    public String getBrand_name() {
        return brand_name;
    }

    public void setBrand_name(String brand_name) {
        this.brand_name = brand_name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

定义一个商品类,重写他的toString方法,同时设置get和set

接下来我们开始写代码

首先我们要获取获取连接,用到了刚才写的工具类

conn = Demo02JDBCUtils.getConnection();

定义一个sql语句

String sql = "select * from goods";

获取执行sql的对象

stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
goods goods = null;
goodss = new ArrayList<goods>();
//6.变量结果集,封装对象
while (rs.next()) {
    //获取数据
    int id = rs.getInt("id");
    String name = rs.getString("name");
    String cate_name = rs.getString("cate_name");
    String brand_name = rs.getString("brand_name");
    int price = rs.getInt("price");
    //创建goods对象,并赋值
    goods = new goods();
    goods.setId(id);
    goods.setPrice(price);
    goods.setName(name);
    goods.setCate_name(cate_name);
    goods.setBrand_name(brand_name);
    goodss.add(goods);
}

遍历这个集合

public static void main(String[] args) {
    List<goods> ls = new Demo01Test().findAll();
    for(goods g : ls){
        System.out.println(g);
    }
}
goods{id=1, name='r510vc 15.6英寸笔记本', cate_name='笔记本', brand_name='华硕', price=3399}
goods{id=2, name='y400n 14.0英寸笔记本电脑', cate_name='笔记本', brand_name='联想', price=4999}
goods{id=3, name='g150th 15.6英寸游戏本', cate_name='游戏本', brand_name='雷神', price=8499}
goods{id=4, name='x550cc 15.6英寸笔记本', cate_name='笔记本', brand_name='华硕', price=2799}
goods{id=5, name='x240 超极本', cate_name='超级本', brand_name='联想', price=4880}
goods{id=6, name='u330p 13.3英寸超极本', cate_name='超级本', brand_name='联想', price=4299}
goods{id=7, name='svp13226scb 触控超极本', cate_name='超级本', brand_name='索尼', price=7999}
goods{id=8, name='ipad mini 7.9英寸平板电脑', cate_name='平板电脑', brand_name='苹果', price=1998}
goods{id=9, name='ipad air 9.7英寸平板电脑', cate_name='平板电脑', brand_name='苹果', price=3388}
goods{id=10, name='ipad mini 配备 retina 显示屏', cate_name='平板电脑', brand_name='苹果', price=2788}
goods{id=11, name='ideacentre c340 20英寸一体电脑 ', cate_name='台式机', brand_name='联想', price=3499}
goods{id=12, name='vostro 3800-r1206 台式电脑', cate_name='台式机', brand_name='戴尔', price=2899}
goods{id=13, name='imac me086ch/a 21.5英寸一体电脑', cate_name='台式机', brand_name='苹果', price=9188}
goods{id=14, name='at7-7414lp 台式电脑 linux )', cate_name='台式机', brand_name='宏碁', price=3699}
goods{id=15, name='z220sff f4f06pa工作站', cate_name='服务器/工作站', brand_name='惠普', price=4288}
goods{id=16, name='poweredge ii服务器', cate_name='服务器/工作站', brand_name='戴尔', price=5388}
goods{id=17, name='mac pro专业级台式电脑', cate_name='服务器/工作站', brand_name='苹果', price=28888}
goods{id=18, name='hmz-t3w 头戴显示设备', cate_name='笔记本配件', brand_name='索尼', price=6999}
goods{id=19, name='商务双肩背包', cate_name='笔记本配件', brand_name='索尼', price=99}
goods{id=20, name='x3250 m4机架式服务器', cate_name='服务器/工作站', brand_name='ibm', price=6888}
goods{id=21, name='商务双肩背包', cate_name='笔记本配件', brand_name='索尼', price=99}

输出结果

事务

事物4大特性简称ACID
保证付款方付款收款方收款

一个很好的处理事务系统,必须具备这些标准特性:

原子性( atomicity)

一个必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性

一致性(consistency)

从一个一致性的状态转换到另一个一致性的状态。 (在前面的例子中,一致性确保了,即使在执行第三、四条语句之间时系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到拟文件中。 )

隔离性(isolation)

通常来说,一个事务所做的修改在最终提交以前,对事务是不可见的。 (在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外的一个账户汇总程序开始运行,则其看到支票账户的余额并没有被减去200美元。 )

持久性(durability)

一旦事务提交,则其所做的修改会永久保存到数据。 (此时即使崩溃系统,修改的数据也不会丢失。 )

操作:
    1. 开启事务
    2. 提交事务
    3. 回滚事务
    3. 使用Connection对象来管理事务
    * 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
    * 在执行sql之前开启事务
    * 提交事务:commit()
    * 当所有sql都执行完提交事务
    * 回滚事务:rollback()
    * 在catch中回滚事务
public class Demo01事务 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt1 = null;
        PreparedStatement pstmt2 = null;
        try {
            //获取连接
            conn = Demo02JDBCUtils.getConnection();
            //定义sql加钱
            String sqla = "update user set password = password - ? where id = ?";
            //定义sql减钱
            String sqlb = "update user set password = password + ? where id = ?";
            //获取执行对象
            pstmt1 = conn.prepareStatement(sqla);
            pstmt2 = conn.prepareStatement(sqlb);
            //设置参数
            pstmt1.setDouble(1,500);
            pstmt1.setInt(2,1);

            pstmt2.setDouble(1,500);
            pstmt2.setInt(2,2);
            //开启事务
            conn.setAutoCommit(false);
            //更新操作,执行sql
            pstmt1.executeUpdate();
            int i = 3/0;
            pstmt2.executeUpdate();
            //事务提交
            conn.commit();
        } catch (SQLException e) {
            //事务的回滚
            try {
                if(conn!=null) {
                    conn.rollback();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            Demo02JDBCUtils.close(pstmt2,conn);
            Demo02JDBCUtils.close(pstmt1,null);
        }

    }
}

这样就完成了一个事务

上一篇:jdbc方法封装直接调用


下一篇:新课程添加