Day28:阿赖耶识

程序写了老半天,说到底就是为了处理资料。

不管处理逻辑使用了多少技术,到头来终究会得出一个结果,并且需要将这个结果储存起来,这就是资料库的用处了。

  • JDBC概念

在Java中我们会使用JDBC来进行资料库的操作,有统一的语法来进行,不过这些都是Java官方高级工程师们的心血结晶,在使用的同时了解一下背後原理也会用得安心一些,发生问题也大概知道要修哪里。

下图就是JDBC的概念图:
JDBC
我们在程序码写的会是JDBC code,而JDBC其实就是一组介面,真正提供介面实作内容的是各家资料库厂商的驱动程序(driver),为什麽要这麽做?

资料库不是只有一种,有好多厂商都推出自家的资料库,赚钱嘛,提供给商用公司就可以收使用权费用。
但这就衍生出一个问题,每家资料库都有自己的通讯协定,这样开发好的程序如果以後要用另一家厂商的资料库,那不就要重写?

所以Java官方提出了JDBC的解决方案,Java开发者只要专心写JDBC code,要用哪家资料库就只要再载入该家资料库的driver,替介面注入实作内容,一切就都可以运作了~ 这也完全符合write once, run everywhere的宗旨。

  • SQL Injection

在我们写JDBC的时候会有Statement以及PreparedStatement两种放入SQL语句的物件,我们都会说用Statement需要直接放入完整的SQL语句,但程序中常常需要用字串连接的方式加上变数,这就导致有SQL Injection的可能了。下面举个例子:

Scanner scanner = new Scanner(System.in);
System.out.println("Please enter username:");
String username = scanner.next();
System.out.println("Please enter password:");
String password = scanner.next();
String sql = "SELECT * FROM USER WHERE username = '" + username + "' and password = '" + password + "'";
Connection conn = DriverManager.getConnection("jdbc:xxxx....", "someUserName", "somePwd");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

范例中会藉由console输入的username和password来寻找资料库中USER表格相对应的user资料。如果这时候我们在console要输入username的时候输入以下:

Please enter username:
Jack' OR 1=1; --
Please enter password:
whatever

密码随便输入没差,我们来看看这样sql会变什麽:

SELECT * FROM USER WHERE username = 'Jack' OR 1=1; --' and password = 'whatever'

"--"在某些资料库中就是注解的符号,所以上面的sql语句在";"後面都被注解掉了,而我们WHERE条件式不管username=什麽,加上了"OR 1=1"就一定会是true,所以这个sql就会找出USER表格中所有的user!

这样的情况就是被SQL Injection了。

  • 交易(Transaction)

    1. ACID
      交易要符合ACID,Atomicity(原子性)、Consistency()、Isolation(隔离性)、Durability(持续性)。
      • Atomicity:一个交易就是一个最小单位,不管其中有多少步骤,都要全部达成或全部撤销。
      • Consistency:资料库中的状态在进行过交易後要有一致性,有点像是原子性用另一个角度来诠释,原子性 着重在交易本身,而一致性看的是被交易操作的资料库。
      • Isolation:不同交易之间不可互相影响,或者互相影响的程度需符合资料库所设定的隔离等级。
      • Durability:交易完成之後,资料库完成交易的状态不会因为任何因素有所改变。
    2. Isolation Level (隔离等级)
      交易与交易之间一定会有时间差的问题,这时候就需要设定隔离等级来进行管理。
      • Read Uncommitted
        目的在解决Lost Update的现象,假如有2个交易都要对同一个栏位进行更改,A交易更改後commit,B交易在A交易commit之前也进行了更改,但是是在A交易commit之後才commit,这时候A交易commit的内容就会被B交易覆盖掉了,称为Lost Update。若资料库隔离等级为Read Uncommitted,在A交易开始後,B交易就只能读取(会读到A交易尚未commit的更改),无法进行更改操作。
      • Read Committed
        假如A交易尚未commit前对某栏位做了更改,这时候B交易读到了这个更改,但是A交易後来rollback,那B交易读取到的资料就是错误的了,这个现象称为Dirty Read。若资料库隔离等级为Read Committed,那B交易在读取的时候,就不会读到A交易尚未commit的变更了,而会是commit过的状态。
      • Repeatable Read
        如果A交易现在没有要进行变更,而是进行读取,在开始交易後读取了某栏位的值,这时交易B开始,对该栏位进行了变更并commit,此时尚未commit的交易A再次进行读取,就会读取到B交易commit过後的结果了,这种现象称为Unrepeatable Read。要解决这个现象可以把资料库隔离等级设定为Repeatable Read。
      • Serializable
        如果A交易开始进行并读取某表格的资料笔数假设是5笔,这时B交易开始并新增了一笔资料後commit,此时A交易再度进行读取就会多了一笔资料,同一交易中读取到的资料笔数不一致,这种现象称为Phantom Read。要解决可以把资料库隔离等级设定为Serializable,但是这样的话资料库效率变差,因为所有事情为了保证不发生Phantom Read就只能让交易循序一个一个来。

<<:  Day29 下拉式选单小实作1

>>:  [Android Studio 30天自我挑战] CradView布局练习

Day 08 「说好的射後不理呢?」多线程环境下的单元测试

今天来聊聊「多线程」的单元测试。 多线程测试的困难点 当系统成长到一个程度,效能的重要性就会慢慢浮现...

[Day28] Security

在网路世界中,安全永远是最最重要的事情,而云端安全当然也不例外。任何的安全问题都来自於人为的疏忽,部...

Day 05 | 资料绑定(一)

今天的内容是页面前後端资料传递,这个部分跟前面相比来说简单许多也比较直觉话。如果以前有写过 Vue....

Day 27 - Greedy

大家好,我是长风青云。原来是27天了,自从我待在家後,对时间的流逝越来越不敏感,乾脆做个月历,放在身...

DAY23 MongoDB 免费监控工具

DAY23 MongoDB 免费监控工具 产品或服务上线最重要的当然是稳定度,大一点的团队会设置监控...