JDBC的入门案列以及JDBC的对事务的管理

JDBC的概念

Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
JDBC本质上是一个接口,是一种规范.
在这里插入图片描述
这里我以Mysql数据库为例子:
通俗来讲就是使用Java代码来访问数据库,对表进行增删改查的操作.

入门案列HelloWorld

	1.首先准备数据库中数据
-- 创建hello表
CREATE TABLE hello(
	id INT,
	`name` VARCHAR(10)
);
-- 添加数据
INSERT INTO hello VALUES(1,'hello');
INSERT INTO hello VALUES(2,'world');

2.导入jar包
https://mvnrepository.com/ 可以在这个maven网站去下载
mysql-connector-java-5.1.37-bin.jar

3.编写java代码

//第一个jdbc程序
public class HelloWorld {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        /*
          第一步:注册驱动 -- 在sql5版本后,这个步奏可以省略,因为在jar包下有个Driver配置文件,已经帮我们注册了
            本身没在内存里面,需要加载才能使用,
            什么情况触发类加载
            1.new
            2.使用静态方法
            3.加载子类的时候,父类也会加载
         */
        Class.forName("com.mysql.jdbc.Driver");
        /*
          第二步:获取连接对象 -- 通过DriverManager的方法获取
            jdbc:mysql  是一种协议和http类似  通过这个协议,就知道是jdbc和mysql的连接
            192.168.93.132 是安装mysql的服务器的ip地址  3306 是对应的端口号,jdbc表示你要操作的那个库,后面的是mysql用户名密码
         */
        Connection connection = DriverManager.getConnection("jdbc:mysql://192.168.93.132:3306/jdbc", "root", "root");

        /*
         第三步:获取语句执行对象
            通过Connection对象获取语句对象
        作用:
            封装sql语句,
            执行sql语句
                1.DML:结果是影响的行数  int类型
                2.Dql:结果是resultSet  结果集
         */
        Statement statement = connection.createStatement();
        /*
        第四步:获取返回的结果集
        执行查询语句,得到结果集对象
            作用:封装mysql服务器响应的数据
         */
        ResultSet resultSet = statement.executeQuery("select * from hello");
        /*
            循环打印每个结果
                resultSet.next()方法是返回一个Boolean的值,如果结果集中有下一行数据,就返回true
         */
        
        while (resultSet.next()) {
            System.out.print(resultSet.getInt("id") + " " + resultSet.getString("name") + "\n");
        }
        //第五步:释放资源
        statement.close();
        resultSet.close();
        connection.close();
    }
}

4.执行结果
在这里插入图片描述

总结Jdbc入门案列

由上面的代码得出jdbc的通用套路分为以下几步
	1.通过类加载器注册驱动
			-- 在sql5版本后,这个步奏可以省略,因为在jar包下有个Driver配置文件,已经帮我们注册了
	2.获取连接对象
			通过DriverManager.getConnection(参数详见代码);获取到连接对象Connection
	3.通过连接对象得到执行语句对象
			通过connection.createStatement();得到Statement执行语句对象
	4.通过statement对象的以下两个方法执行语句
	 		statement.executeQuery(sql语句);-->这是执行的是DQL语句,返回的是ResultSet结果集,这个结果集相当于List<Map<String,Object>>
    		statement.executeUpdate(sql语句);-->这是执行的是DML语句,返回的是影响的行数

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

解决SQL注入

从上面的入门案列中我们使用的执行语句对象是statement,这个对象在执行sql语句的时候是对sql语句进行字符串拼接,所以会存在sql注入风险
PreparedStatement
它的父接口是Statement,Prepared准备好的SQL语句。MySQL中的语句也是要编译以后才执行,编译是需要消耗时间的。
比父接口更强大的地方:
1.SQL语句会预先编译,执行效率会更高。
2.解决SQL注入的问题,更安全
3.SQL语句代码的可读性更好,所有要替换的参数使用占位符,占位符是?问号

   /**
 * 模拟登录解决sql注入的问题,对入门案列的改造
 */
public class LoginUser {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        /*
          第一步:注册驱动 -- 在sql5版本后,这个步奏可以省略,因为在jar包下有个Driver配置文件,已经帮我们注册了
         */
        Class.forName("com.mysql.jdbc.Driver");
        /*
          第二步:获取连接对象 -- 通过DriverManager的方法获取
         */
        Connection connection = DriverManager.getConnection("jdbc:mysql://192.168.93.132:3306/jdbc", "root", "root");

        /*
         第三步:获取预编译语句执行对象
            通过Connection对象获取预编译语句对象
         */
        //定义两个字符串来模拟用户传递的用户名密码,
        String username = "user";
        String password = "mima";
        //通过连接对象获取预编译语句对象
        PreparedStatement pst = connection.prepareStatement("select * from user where username=? and password=?");
        //传递参数:参数1表示语句中的第一个问号,2就是第二个问号
        pst.setString(1,username);
        pst.setString(2,password);
        //执行查询方法,返回结果集
        ResultSet resultSet = pst.executeQuery();
        /*
        第四步:获取返回的结果集
        执行查询语句,得到结果集对象
            作用:封装mysql服务器响应的数据
         */
        while (resultSet.next()) {
            //如果查询出有结果集,表示有这个用户,就打印登录成功
            System.out.println("登录成功");
        }
        //第五步:释放资源
        pst.close();
        resultSet.close();
        connection.close();
    }
}


JDBC对事务的管理

通过连接对象中的方法来实现事务管理:注意事务管理的连接对象要是同一个

Connection接口中与事务有关的方法:

void setAutoCommit(boolean autoCommit) 设置事务的提交方式true 表示自动提交false 表示手动提交如果要开启事务,设置为false
void commit() 提交事务
void rollback() 回滚事务

目标
使用JDBC来处理事务:实现银行转账的操作

1.数据准备

-- 准备数据,创建账户表
CREATE TABLE `account` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT NULL,
`money` DOUBLE DEFAULT NULL,
PRIMARY KEY (`id`)
);

-- 添加数据
INSERT INTO account VALUES(NULL,'小付',1000),(NULL,'小花',1000);

表中的数据:
在这里插入图片描述
JDBC控制事务模拟转账代码:

扫描二维码关注公众号,回复: 11371137 查看本文章
public class ZhuanZhang {
    public static void main(String[] args) throws Exception {

        //调用转账方法,让A给B转100元钱
        zhuanQian("小付","小花",900D,1100D);
    }

    /**
     *假设2个人都是1000 元
     * @param nameA 转钱的用户
     * @param nameB 收钱的用户
     * @param moneyA 模拟转多少钱后更新表中的钱
     * @param moneyB 模拟收多少钱后更新表中的钱
     */
    public static void zhuanQian(String nameA,String nameB,Double moneyA,Double moneyB){
        Connection connection = null;
        //获取连接对象
        try {
            connection = DriverManager.getConnection("jdbc:mysql://192.168.93.132:3306/jdbc", "root", "root");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        try {
            //开启事务  false表示关闭自动提交事务
            connection.setAutoCommit(false);

            //得到预编译语句对象,先执行减钱的一方
            PreparedStatement pstA = connection.prepareStatement("UPDATE account SET money = ? WHERE NAME = ?");
            pstA.setDouble(1,moneyA);
            pstA.setString(2,nameA);
            pstA.executeUpdate();

            //得到预编译对象,执行加钱的一方
            PreparedStatement pstB = connection.prepareStatement("UPDATE account SET money = ? WHERE NAME = ?");
            pstB.setDouble(1,moneyB);
            pstB.setString(2,nameB);
            pstB.executeUpdate();

            //执行到这里说明都没有问题就提交事务
            connection.commit();
        } catch (SQLException throwables) {
            //说明sql语句出现异常,就回滚事务,让数据回到最初的时候
            try {
                connection.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        } finally {
            //释放资源
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

执行代码后数据库信息:
在这里插入图片描述
我们先还原数据库的数据,都为1000元:
然后在代码中制造一个异常:

            //得到预编译语句对象,先执行减钱的一方
            PreparedStatement pstA = connection.prepareStatement("UPDATE account SET money = ? WHERE NAME = ?");
            pstA.setDouble(1,moneyA);
            pstA.setString(2,nameA);
            pstA.executeUpdate();

            //制造异常 制造一个通用异常
            int a = 1/0;

            //得到预编译对象,执行加钱的一方
            PreparedStatement pstB = connection.prepareStatement("UPDATE account SET money = ? WHERE NAME = ?");
            pstB.setDouble(1,moneyB);
            pstB.setString(2,nameB);
            pstB.executeUpdate();

执行发现数据库中的数据没有任何变化,控制台爆出异常
在这里插入图片描述
然后查询数据库发现数据并没有发生改变
在这里插入图片描述

所以我们发现当代码执行中出现异常,进行了事务回滚.

猜你喜欢

转载自blog.csdn.net/fushuaiCSDN/article/details/106735670