JavaSE--jdbc编程
JDBC全称为:Java Data Base Connectivity (java数据库连接),可以为多种数据库提供统一的访问。JDBC是sun开发的一套数据库访问编程接口,是一种SQL级的API。它是由java语言编写完成,所以具有很好的跨平台特性,使用JDBC编写的数据库应用程序可以在任何支持java的平台上运行,而不必在不同的平台上编写不同的应用程序,功能类似于windows操作系统提供的ODBC服务,目前主流的数据库操作框架都是以JDBC为基础进行开发的,所以JDBC是JAVA连接数据以及操作的基础入口。
一、连接数据库
1.导入驱动jar包
2.连接数据库
①加载驱动程序:Class.forName(driverClass) //将类加载到内存中
加载mysql驱动:Class.forName("com.mysql.jdbc.Driver");
加载oracle驱动:Class.forName("oracle.jdbc.driver.OracleDriver");
②获得数据库连接
DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db",u ser,password);
DriverManager.gerConnection(URL,user,password);
③创建Statement对象:conn.createStatement();
④向数据库发送SQL命令
⑤处理数据库的返回结果(ResultSet类)
二、事务Transaction(ACID)
数据库事务是指作为单个逻辑工作单元执行的一系列操作,这些操作要么完全执行要么一个都不执行。对于数据库来说事务是对数据操作的一种确认手段,以保证数据库操作的正确性。对于事务来说它存在的条件是一个相同数据库连接,所以保证事务的前提是提供一个一致的数据库连接。
1.事物的特性
①原子性(Atomicity)
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
②一致性(Consistency)
一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。
③隔离性(Isolation)
隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。
④持久性(Durability)
在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
2.事务的隔离级别
隔离级别 |
脏读 |
不可重复读 |
幻读 |
读未提交(Read Uncommitted) |
√ |
√ |
√ |
读已提交(Read Committed) |
× |
√ |
√ |
可重复读(Repeatable Read) |
× |
× |
√ |
可串行化(Serializable) |
× |
× |
× |
3.事务执行操作
1 Connect.setAutoCommit(false); //关闭SQL自动提交,开启事务
2 Connect.commit(); //提交事务
3 Connect.rollback(); //回滚事务
三、常见问题
1.SQL注入
SQL注入可以分为平台层注入和代码层注入。前者由不安全的数据库配置或数据库平台的漏洞所致;后者主要是由于程序员对输入未进行细致地过滤,从而执行了非法的数据查询。基于此,SQL注入的产生原因通常表现在以下几方面:①不当的类型处理;②不安全的数据库配置;③不合理的查询集处理;④不当的错误处理;⑤转义字符处理不合适;⑥多个提交处理不当。
①防护手段
对用户提交的数据进行安全性验证,数据合法才能提交到服务器,其次是尽量不使用Statement对象处理SQL语句,不使用动态生成的的SQL拼接语句,尽量使用能对SQL语句进行预编译的PrepareStatement对象处理SQL语句。
2.日期存储
在JDBC中使用java.sql.Date类型来才做日期,它继承与java.util.Date,它是一种为数据库存储日期而设计的一种类型,所以要向数据库直接保存日期格式的话就需要将日期类型做相应的转换,当然使用日期浮点数表示来存储当前具体时间也是合理的,而且数据较为精确。
3.大数据长文本存储
对于一般的字符串存储使用VARCHAR足以应付,但对于超大的字符串文本使用VARCHAR就不太合理了,此时应当使用数据库的CLOB类型保存超大型文本,使用setCharacterStream()设置文本字符流到数据库,使用getClob()方法取出Clob对象,然后再取出流转为字符串对象。
对于超大的二进制数据一般使用Blob类型进行保存,使用字节输入输出流对数据进行存取操作,使用setBinaryStream()方法设置数据到数据库,使用getBlob取得Blob对象,取得输出流即可读出数据。
4.批处理操作
对于短时间内进行的大量数据操作不应该多次的访问数据库,应该将所有的数据操作指令结合在一起后统一对数据库进行操作,使用PreparedStatement的addBatch()将数据循环封装到Statement当中,最后用PreparedStatement的executeBatch()执行所有的操作。
5.可更新和可滚动的结果集
①取得结果集
1 Statement s = conn.createStatement(type,concurrency); 2 PreparedStatement s =conn.preparedStatement(command,type,concurrency);
type |
TYPE_FORWARD_ONLY |
结果集不能滚动(默认值) |
|
TYPE_SCROLL_INSENSITIVE |
结果集可以滚动,但对数据库变化不敏感 |
|
TYPE_SCROLL_SENSITIVE |
结果集可以滚动,对数据库变化敏感 |
concurrency |
CONCUR_READ_ONLY |
结果集不能用于更新数据库(默认值) |
|
CONCUR_UPDATABLE |
结果集可以用于更新数据库 |
②滚动操作
- 向后滚动:rs.previous();如果游标位于一个实际的行上,那么该方法将返回true;如果游标位于第一行之前,那么就返回false;
- 将游标向后或向前移动多行:rs.relative(n);n为正数,向前移动;或负数,向后移动;n为0,不移动;
- 将游标设置到指定的行号上:rs.absolute(n);
- 调用以下方法将返回当前行的行号:int curRow = rs.getRow();
- 结果的第一行是1,而不是0;如果返回0,那么当前游标不在任何行上,它要么位于第一行前,或最后一行之后;(干货——可滚动结果集的第一行的index是1,而不是0)
- 其他操作:first,last,beforeFirst,afterLast方法,与isFirst ,isLast, isBeforeFirst,isAfterLast方法;
③更新操作
并非所有的查询都会返回可更新的结果集,如果查询涉及多个表的连接操作,那么它所产生的结果集将是不可更新的,可以调用 ResultSet 接口中的 getConcurrency方法来确定结果集是否是可更新的;
6.分页查询
①MySQL 数据库分页查询
MySQL数据库实现分页比较简单,提供了LIMIT函数。一般只需要直接写到sql语句后面就行了。LIMIT子句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如果给出两个参数,第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数。例如:
1 select * from table WHERE … LIMIT 10; #返回前10行 2 select * from table WHERE … LIMIT 0,10; #返回前10行 3 select * from table WHERE … LIMIT 10,20; #返回第10-20行数据
②ORCALE数据库分页查询
ORCALE数据库实现分页查询可以使用row_number()函数或者使用rownum 虚列两种方法。
- 第一种:利用分析函数row_number() 方法
1 select * from ( select t.*,row_number() over (order by t1.id) rowno from TABLE1 ) 2 where rowno between 21 and 40;
- 第二种:直接使用rownum 虚列
1 select * from (select t.*,rownum as rowno from TABLE1 ) 2 where rowno between 10 and 20;
这两种方法比较,显然第二种方法比较好。因为不用order by语句,会提高检索数据的速度的,尤其数据量越大时,第二种方法快速检索数据越明显。