MySQL中的事务相关属性以及JDBC编程

MySQL中的事务相关属性以及JDBC编程

事务🌛

出现的原因可以简言之:有些事情天然就应该要么一次性做完,要么就别做,比如zfb转账,账户A扣款必须伴随着账户B的余额增加,如果这两件事被割离开来,显然是不合理的.所以说,一个事务的意思:将若干个独立的操作打包成一个整体.

好处:事务中的若干操作如果只是执行了一部分,后续出现了一些原因导致剩余的操作不可继续执行,那此时就可以回滚,就好像什么也没发生过一样.回滚的实现主要依托于日志和数据库内置的一些表来完成的.

事务的基本特性☔️

  1. 原子性,上述的案例所描述的就是原子性,要么就一次性执行完所有的操作,要么就一个操作也别执行
  2. 一执行:事务执行前后,各方面数据必须是具备合理性的.
  3. 持久性:事务的写操作,是会对服务器硬盘上的数据做出修改的,这种修改是具备持久性的.
  4. 隔离性:下面终点介绍

事务的隔离性📦

事务的原子性能够保证处于一个线程中同一个事务中的操作能够"一口气执行完",但是在多线程并发时,多线程对同一份数据进行读或者写的时候就容易出现线程安全问题,挥着说白了就是容易出现bug(出现个预期不符的结果).

举例:

  1. 如A要在代码仓库中提交代码,供B去学习,并且A可以随时改动仓库中的代码,巧了,A在该代码的时候,B恰好看到了A敲的代码,B很开心的读到了A的代码,但是A刚才打出来的代码并不是真正想打的代码,A打错了,所以A就要修改呀,但是B已经读走了一份错误的代码,这里锁描述的场景就是出现了"脏读"问题!

    如何处理脏读呢?:

    只要保证A在写代码的时候,别人获取不到(读不到)这份代码就可以了,只有A真正操作完了,B才能去读这一份代码,其实就是给写操作进行加锁,就是A写代码的时候,别人是不可以进行读代码的操作.

  2. 还是上述写代码的交代码的过程,1解决了脏读问题,但是B因为是在学习,他需要反复的去读这个代码,但是学了没一会,缺德的A又去把代码改了改,那B就读不到之前在学的代码了,这就出现了"不可重复读"的问题!

    如何解决不可重复读的问题:

    只需要给B读代码的操作进行上锁即可,让B在读代码的时候A不可以对代码进行修改,因为对B来说可能B的事务就是把代码读10遍,事务一旦开始执行,B就一直在读,A无法抢占B上锁的对象.

  3. 上述分别将A的写操作和B的读操作都上了锁,这样有一个不好的地方,就是如果B学的很慢,他要学很久,那我A岂不是要一直干等着?既然B正在读的代码我A不能动,A可以去"动"其他的代码呀,但是对B来说一个大仓库里,B可能学的不只是一份代码,A把另一份代码修改了之后,整个仓库的结果集相当于收到了修改,那B所能查询到的结果集就发了变化,所以此时产生了幻读问题.

    如何解决幻读问题呢:

    B和A约定好,B在学习的时候,A既不要动B正在读的代码,也不要动仓库里的别的代码,就可以解决啦,那此时读和写的操作完全被串行式执行了.此时的并发程度是最低的.


MySQL中的事务隔离级别🏷

  1. read uncommitted:字面意思就是还没提交的数据都读了,那不就是容易出现所谓的脏读问题吗,此时是什么锁也没加的,此时的并发程度是最高的

    此时容易出现的问题:脏读/不可重复读/幻读

  2. read committed:字面意思是,只能读提交了的数据,相当于A真的修改完代码,把代码提交到仓库了,B才能去读代码,相当于给A的写加了锁,解决了脏读问题

    此时容易出现的问题:不可重复读/幻读

  3. repeatable read:字面意思就是可重复读,给读写都上锁了,解决了不可重复读的问题

    此时容易出现的问题:幻读

  4. serializable:串行式执行,可解决上锁所有的问题.


MySQL的JDBC编程🍔

JDBC是java提供一组数据库编程接口,用以适应当下很多的数据库的操作.相当于作了一个大一统,学习java的程序员只需要知道JDBC如何去操作,就可实现对多种数据库的操作了.如果诞生了新的数据库,那这个数据库生产厂商就应当提供各自的"数据库驱动包",来和java的JDBC的API进行对接,java就是这么牛.


JDBC编程准备工作🤙

  1. 创建项目
  2. 引入依赖:就是要下载mysql的数据库驱动包,让mysql的自身API能和jdbc编程风格相适应.由于mysql已经被oracle收购了,所以mysql的数据驱动包要去oracle的官网下载,但是oracle的官网下载个东西非常的麻烦,那java的开发大佬又出现了,直接实现了一个中央仓库:maven,这个仓库里就几乎涵盖了我们平常所要使用的第三方库,而且用起来非常的方便,所以我们就去maven上下载驱动包吧~中央仓库官网:https://mvnrepository.com/

下载此处的jar包即可.

接下来就是把下载好的驱动包导入到项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VTpvb6S8-1650117826788)(C:\Users\lebronHArden\AppData\Roaming\Typora\typora-user-images\image-20220416210657723.png)]

再右键JDBC目录,选择add as library,确定即可.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qaGGNXvV-1650117826789)(C:\Users\lebronHArden\AppData\Roaming\Typora\typora-user-images\image-20220416210809020.png)]

此时JDBC目录下有这么一个jar包,就说明操作成功了.只有这样,才能把这个jar包引入到项目当中,此时项目才会从jar里面读取内部的.class.


JDBC代码的编写🏭

  1. 创建DataSource对象,这个对象用以描述JDBC编程所操作的服务器在哪

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UUtRR2ZW-1650117826791)(C:\Users\lebronHArden\AppData\Roaming\Typora\typora-user-images\image-20220416211232095.png)]

    其中的MysqlDaaSource就是来自于jar包.

    接下来就要对数据库的地址进行设置,分别是打开服务器的房门在哪(ip,端口号),以及用以登录服务器的用户名和密码

    URL:uniform resource locator:唯一资源定位符,描述了互联网上的一个资源所在的位置.

    此处我们的服务器就是在自己的主机上,所以,ip直接用环回ip即可,mysql服务器的端口号在安装mysql的时候就已经默认设置成3306了.

    所以,16-18行代码可以写成:

    public class Demo1 {
        public static void main(String[] args) {
            DataSource dataSource=new MysqlDataSource();
            //设置数据库的地址(下述的三个操作都是向下转型,去调用jar包里属于MysqlDataSource类的方法)
            //含义:用于mysql的jdbc的url,ip地址是环回ip,端口号就是服务器的端口号,java是数据库的名字,字符集,传输过程是否加密,此处就是不加密
            ((MysqlDataSource) dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java?characterEncoding=utf8&useSSL=false");
            //设置进入数据库的用户名
            ((MysqlDataSource) dataSource).setUser("root");
            //设置进入数据库的密码
            ((MysqlDataSource) dataSource).setPassword("把密码写在这就可以了");
        }
    }
    
  2. 剩余部分直接给出吧,注意事项都写在注释里头了.

            //2.让代码和数据库建立连接
            //注意前面的Connection是sql包下的connection,别搞错了
            Connection connection=dataSource.getConnection();
    
            //3.操作数据库
            //主要还是构造sql语句,此时的sql字符串不需要在带有;因为这只是在cmd窗口的命令行结束标志
            String sql="insert into exam_result values(10,'李四',99,99,99)";
            //将上述的sql包装成一个语句对象
            PreparedStatement statement = connection.prepareStatement(sql);
    
            //4.执行sql(增删改都是用Update,查要用Query)
            int ret = statement.executeUpdate();//返回的是影响了几行的整数
            System.out.println(ret);
    
            //5.释放资源
            statement.close();
            connection.close();
    

    能打印1,就说明操作成功个了,去cmd窗口看看是不是插入成功了?>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-289ioGgs-1650117826791)(C:\Users\lebronHArden\AppData\Roaming\Typora\typora-user-images\image-20220416213717118.png)]

说明操作成功.


上述实现了用jdbc的API对自己主机上的服务器中的数据库进行了插入记录的操作.但是上述代码中有一个比较大的缺点,就是这个sql语句的构建比较死板,如果能实现成可以让用户随便输入想要操作的sql语句就好了,就相当于有了一个图形化界面去操作数据库啦!

//3.操作数据库
        System.out.println("请输入id:");
        int id=scanner.nextInt();
        System.out.println("请输入姓名:");
        String name=scanner.next();
        System.out.println("请输入语文成绩:");
        int chinese=scanner.nextInt();
        System.out.println("请输入数学成绩:");
        int math=scanner.nextInt();
        System.out.println("请输入英语成绩:");
        int english=scanner.nextInt();
        //主要还是构造sql语句,此时的sql字符串不需要在带有;因为这只是在cmd窗口的命令行结束标志
        String sql="insert into exam_result values(?,?,?,?,?)";
        //将上述的sql包装成一个语句对象
        PreparedStatement statement = connection.prepareStatement(sql);
        //对sql进行修改
        statement.setInt(1,id);
        statement.setString(2,name);
        statement.setInt(3,chinese);
        statement.setInt(4,math);
        statement.setInt(5,english);
        System.out.println(statement);

        //4.执行sql(增删改都是用Update,查要用Query)
        int ret = statement.executeUpdate();//返回的是影响了几行的整数
        System.out.println(ret);

        //5.释放资源
        statement.close();
        connection.close();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zPXT6faM-1650117826792)(C:\Users\lebronHArden\AppData\Roaming\Typora\typora-user-images\image-20220416214748158.png)]

操作成功!


上述只是针对(增删改时的操作),那对查呢?

多了一个步骤,需要遍历结果集

        Connection connection=dataSource.getConnection();

        String sql="select * from exam_result";
        PreparedStatement statement = connection.prepareStatement(sql);

        ResultSet resultSet=statement.executeQuery();//相当于一个以记录为单位的容器

        while(resultSet.next()){
            int id=resultSet.getInt("id");
            String name=resultSet.getString("name");
            int chinese=resultSet.getInt("chinese");
            int math=resultSet.getInt("math");
            int english=resultSet.getInt("english");

            System.out.println("id="+id+",chinese="+chinese+",math="+math+",english="+english);
        }

        //释放资源,先开的资源后释放
        resultSet.close();
        statement.close();
        connection.close();
    }

这里与上述代码的不同

  1. sql执行完的返回类型不同,前面的增删改都是返回被修改的记录的条数(一个整数),而此处返回的是以记录为单位的一个集合,需要遍历集合才能看到这个集合的每一条记录的具体内容
  2. 释放资源时多了一个资源的释放,就是ResultSet的释放
  • 19
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值