Java基础知识(十一)——Java数据库操作

 

1、如何通过JDBC访问数据库

Java数据库连接(Java DataBase Connectivity,JDBC)用于在Java程序中实现数据库操作功能,它提供了执行SQL语句、访问各种数据库的方法,并为各种不同的数据库提供统一的操作接口,java.sql包中包含了JDBC操作数据库的所有类。通过JDBC访问数据库一般有如下几个步骤:

1)加载JDBC驱动器。

将数据库的JDBC驱动加载到classpath中,在基于JavaEE的Web应用开发过程中,通常要把目标数据库产品的JDBC驱动复制到WEB-INF/lib下。(假如是Maven项目的话直接引入相应的数据库驱动jar包的仓库地址即可)

2)加载JDBC驱动,并将其注册到DriverManager中。

一般使用反射Class.forName(String drivelName)

3)建立数据库连接,取得Connection对象。

一般通过DriverManager.getConnection(url,username,passwd)方法实现,其中,url表示连接数据库的字符串,usermame表示连接数据库的用户名,passwd表示连接数据库的密码。

4)建立Statement 对象或是PreparedStatement对象。

5)执行SQL语句。

6)访问结果集ResultSet对象。

7)依次将ResultSet、Statement、PreparedStatement、Connection对象关闭,释放掉所占用资源,

例如rs.close(),con.close()等。为什么要这么做呢?原因在于JDBC驱动在底层通常都是通过网络IO实现SQL命令与数据传输的。

2、JDBC处理事务采用什么方法

一个事务是由一条或多条对数据库操作的SQL语句所组成的一个不可分割的工作单元,只有当事务中的所有操作都正常执行完了,整个事务才会被提交给数据库。在JDBC中,一般是通过commit()方法或rolback()方法来结束事务的操作。其中commit()方法表示完成对事务的提交rollback()方法表示完成事务回滚,多用于在处理事务的过程中出现了异常的情况,这两种方法都位于java.sql.Connection类中。一般而言,事务默认操作是自动提交,即操作成功后,系统将自动调用commit()方法,否则将调用rollback()方法。

当然,在JDBC中,也可以通过调用setAutoCommit(false)方法来禁止自动提交,然后就可以把多个数据库操作的表达式作为一个事务,在操作完成后调用commit()方法实现整体提交,如果其中一个表达式操作失败,就会抛出异常而不会调用commit()方法。在这种情况下,就可以在异常捕获的代码块中调用rolback()方法进行事务回滚。通过此种方法可以保持对数据库的多次操作后,数据仍然保持一致性。

引申:JDBC有哪些事务隔离级别?

为了解决与“多个线程请求相同数据”相关的问题,事务之间通常会用相互隔离开。

如今,大多数主流的数据库支持不同类型的锁。因此,JDBC API支持不同类型的事务,它们由Connection对象指派或确定。在JDBC中,定义了以下5种事务隔离级别

1)TRANSACTION_NONE JDB。

不支持事务。

2)TRANSACTION_READ_UNCOMMITTED。

未提交读。说明在提交前一个事务可以看到另一个事务的变化。这样读“脏”数据、不可重复读和虚读都是允许的

3)TRANSACTION_READ_COMMITTED。

已提交读。说明读取未提交的数据是不允许的。这个级别仍然允许不可重复读和虚读产生。

4)TRANSACTION_REPEATABLE_READ。

可重复读。说明事务保证能够再次读取相同的数据而不会失败,但虚读仍然会出现。

5)TRANSACTION_SERIALIZABLE。

可序列化。是最高的事务级别,它防止读“脏”数据、不可重复读和虚读。

(备注:

①读“脏”数据。

一个事务读取了另一个事务尚未提交的数据,例如,当事务A与事务B并发执行时,当事务A更新后,事务B查询读取到A尚未提交的数据,此时事务A回滚,则事务B读到的数据是无效的“脏”数据。

②不可重复读。

一个事务的操作导致另一个事务前后两次读取到不同的数据,例如,当事务A与事务B并发执行时,当事务B查询读取数据后,事务A更新操作更改事务B查询到的数据,此时事务B再次读去该数据,发现前后两次的数据不一样。

③虚读。

一个事务的操作导致另一个事务前后两次查询的结果数据量不同,例如,当事务A与事务B并发执行时,当事务B查询读取数据后,事务A新增或删除了一条满足事务A的查询条件的记录,此时,事务B再次查询,发现查询到前次不存在的记录,或者前次的某个记录不见了。)

事务隔离级别越高,为避免冲突所花的精力也就越多。可以通过Connection对象的conn.setTransactionLevel()方法来设置隔离级别,通过conn.getTransactionlsolation()方法来确定当前事务的级别。
 

3、Class.forName的作用是什么

在Java语言中,任何类只有被装载到JVM上才能运行Class.forName()方法的作用就是把类加载到JVM中,它会返回一个与带有给定字符串名的类或接口相关联的Class对象,并且JVM会加载这个类,同时JVM会执行该类的静态代码段。

在使用JDBC连接数据库前,一般都会调用Class.forName("com.mysql.jdbc.Driver”)方法来加载JDBC驱动,那么是否一定需要调用这个方法呢?如果是,那为什么要调用这个方法呢?其实,并不一定非要调用这种方法,例如Testt=(Test)Class.forName(“Test”).newInstance()语句和Testt=new Test()语句就具有相同的效果,所以使用new也可以,但二者的区别也非常明显:创建对象的方式不同。前者使用类加载机制,后者是创建了一个新的类。使用第一种方法往往能提高软件的可扩展性,例如,一个软件项目开发后会被多家公司来使用,每家公司的处理流程大致相同,只有个别公司的业务逻辑不同,在开发过程中,完全可以把不通用的地方抽取出来定义成一个接口Bussinesslnterface,针对每个公司不同的业务流程定义不同的实现类sub1、sub2、sub3等,通过创建不同的子类来完成不同公司的业务需求。

为了达到良好的可扩展性,可以把子类采用配置文件的方式放到XML文件中。在程序部署时,只需要从读配置文件中读取类名className,然后采用BussinessInterface b=(BussinessInterface)Class.forName(className).newlnstance()创建实例即可提高开发人员的开发效率。当以后再有新的需求时,即使开发了新的子类,也不需要修改创建实例的代码,只需要修改配置文件即可,从而使得程序具有很好的可扩展性。

JDBC规范中要求Driver类在使用前必须向DriverManager注册自己,所以,当执行Class.forName("com.mysql.jdbc.Driver")时,JVM会加载名字为“com.mysql.jdbc.Driver"对应的Driver类,而com.mysql.Driver类的实现如下例所示:


在调用Class.forName()方法时,这个Driver类被加载了,由于静态部分被执行,因此Driver 也被注册到DriverManager中。

PS: 这里使用的是Java中的反射机制去动态加载数据库驱动的方式(欲了解Java的反射机制可以参阅文章: https://blog.csdn.net/wu631464569/article/details/102244573)。

 

4、Statement、PreparedStatement 和CallableStatement有什么区别

Statement用于执行不带参数的简单SQL语句,并返回它所生成结果的对象|每次执行SQL语句时,数据库都要编译该SQL语句。以下是一个最简单的SQL语句:

PreparedStatement表示预编译的SQL语句的对象,用于执行带参数的预编译SQL语句

CallableStatement则提供了用来调用数据库中存储过程的接口,如果有输出参数要注册,说明是输出参数。下面给出一个使用PreparedStatement的例子:

虽然Statement对象与PreparedStatement对象能够完成相同的功能,但相比之下,PreparedStatement具有以下优点:

1)效率更高。

在使用PreparedStatement对象执行SQL命令时,命令会被数据库进行编译和解析,并放到命令缓冲区。然后,每当执行同一个PreparedStatement对象时,由于在缓冲区中可以发现预编译的命令,虽然它会被再解析一次,但不会被再次编译,是可以重复使用的,能够有效提高系统性能,因此,如果要执行插入、更新、删除等操作,最好使用PreparedStatement。鉴于此,PreparedStatement适用于存在大量用户的企业级应用软件中

2)代码可读性和可维护性更好。

以下两种方法分别使用Statement 与PreparedStatement来执行SQL语句,显然方法2具有更好的可读性。


3)安全性更好。

使用PreparedStatement能够预防SQL注入攻击所谓SQL注入,指的是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器,达到执行恶意SQL命令的目的注入只对SQL语句的编译过程有破坏作用而执行阶段只是把输入串作为数据处理,不再需要对SQL语句进行解析,因此也就避免了类似select* from user where name='aa'and password='bb'or1=1的SQL注入问题的发生。

CallableStatementprepareCall()方法所创建,它为所有DBMS(Database Management System,数据库管理系统)提供了一种以标准形式调用已储存过程的方法。它从PreparedStatement中继承了用于处理输入参数的方法,而且还增加了调用数据库中的存储过程和函数以及设置输出类型参数的功能。


5、getString()方法与getObject()方法有什么区别

 

JDBC提供了getString()、getlnt()和getData()等方法从ResultSet中获取数据,当查询结果集中的数据量较小时,不用考虑性能,使用这些方法完全能够满足需求,但是当查询结果集中的数据量非常大时,则会抛出异常:OracleException未处理:0RA-01000:maximum open cursors exceeded(以访问Oracle 数据库为例)。而通常情况下,使用getObject()方法就可以解决这个问题。

getString()或getlnt()等方法在被调用时,程序会一次性地把数据都放到内存中,然后通过调用ResultSet的next()和getString()等方法来获取数据。当数据量大到内存中放不下时就会抛出异常,而使用getObject()方法就不会这种问题,因为数据不会一次性被读到内存中,每次调用时会直接从数据库中去获取数据,因此使用这种方法不会因为数据量过大而出错。
 

6、使用JDBC时需要注意哪些问题

在使用JDBC编程时,首先需要建立于数据库的连接,才能完成对数据库的访问,由于与数据库的连接是非常重要的资源。JDBC连接池提供了JDBC连接定义和数目有限的连接,如果连接数量不够,就需要长时间的等待。不正常关闭JDBC连接会导致等待回收无效的JDBC连接。只有正常的关闭和释放JDBC连接,JDBC资源才可以被快速地重用,从而使得系统性能得到改善。因此在编程时,一定要保证释放不再使用的连接。

一般来讲,在使用JDBC访问数据库时,createStatement和prepareStatement最好放在循环外面,而且使用了这些Statement后,需要及时关闭。最好是在执行了一次executeQuery、executeUpdate等之后,如果不需要使用结果集(ResultSet)的数据,就马上将Statment关闭。因为每次执行conn.createStatement()或conn.prepareStatement(),实际上都相当于在数据库中打开了一个cursor(游标),如果把对这两个方法的调用放到循环内,会一直不停地打开cursor。
如果不能及时地关闭,会导致程序抛出异常。
 

7、什么是DO

Java数据对象(Java Data Object,JDO)是一个用于存取某种数据仓库中的对象的标准化API,它使开发人员能够间接地访问数据库。

JDO是JDBC的一个补充,它提供了透明的对象存储,因此对开发人员来说,存储数据对象完全不需要额外的代码(例如JDBC API的使用)。这些烦琐的工作已经转移到JDO产品提供商身上,使开发人员解脱出来,从而集中时间和精力在业务逻辑上。另外,相较于JDBC,JDO更灵活、更通用,它提供了到任何数据底层的存储功能,例如关系数据库、文件、XML以及对象数据库管理系统(Object Database Management System,ODBMS)等,使得应用可移植性更强。
 

8、JDBC与Hibernate 有什么区别

HibernateJDBC的封装,采用配置文件的形式将数据库的连接参数写到XML文件中,至于对数据库的访问还是通过JDBC来完成的。

Hibermate是一个持久层框架,它将表的信息映射到XML文件中,再从XML文件映射到相应的持久化类中,这样可以使用Hibernate 独特的查询语言Hibernate 查询语言(Hibernate Query Language,HQL)了。Hibernate的HQL查询语句返回的是List<Object[.]>类,而JDBC通过statement返回的查询结果是ResultSet并且有时候需要自己封装到List中。另外一个重要区别在于,Hibernate具有访问层(DAO类层,DA0全称为Data Access Object数据访问接口,意为数据访问接口),该层是HQL查询语句唯一出现的位置,再往上层则不会出现查询语句,而JDBC可以随时连接随时访问,例如有100个类都有SQL查询语句,如果表名改变了,那么要使用JDBC的方式,就必须重写所有查询语句,而采用Hibernate的方式只需修改DAO层的类即可,因此Hibernate具有很好的维护性和扩展性。
 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值