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

MySQL中的事务相关属性以及JDBC编程,第1张

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

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

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

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

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

举例:

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

如何处理脏读呢?:

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

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

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

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

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

如何解决幻读问题呢:

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


MySQL中的事务隔离级别🏷

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

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

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

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

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

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

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


MySQL的JDBC编程🍔

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


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

下载此处的jar包即可.

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

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

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


JDBC代码的编写🏭

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

其中的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.让代码和数据库建立连接
        //注意前面的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窗口看看是不是插入成功了?>

说明 *** 作成功.


上述实现了用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();

*** 作成功!


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

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

        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();
    }

这里与上述代码的不同

sql执行完的返回类型不同,前面的增删改都是返回被修改的记录的条数(一个整数),而此处返回的是以记录为单位的一个集合,需要遍历集合才能看到这个集合的每一条记录的具体内容释放资源时多了一个资源的释放,就是ResultSet的释放

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/991774.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存