JDBC总结
一、什么是JDBC
1、sun公司统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。其中JDBC驱动程序管理器是JDBC体系结构的核心。JDBC全称为:Java Data Base Connectivity。java数据库连接),它主要由接口组成。
2、组成JDBC的2个包:
(1) java.sql
(2) javax.sql
3、开发JDBC应用需要以上2个包的支持外,还需要导入相应JDBC的数据库实现(即数据库驱动)。
二、第一个JDBC程序
程序步骤:
1、搭建实验环境 :
(1)、在mysql中创建一个库,并创建user表和插入表的数据。
(2)、新建一个Java工程,并导入数据驱动。
2、载入驱动
Class.forName(“com.mysql.jdbc.Driver”);
3、建立连接
Connection con=new Connection;
String url=”jdbc:mysql://localhost:3306:/库名”;
String username=”roor”;
String password=”root”;
con=DriverManager.getConnection(“url”,”username”,”password”);
4、生成Statement对象,提交查询语句,返回结果集
Statement st=new Statement();
st=con.CreateStatement();
String sql=”Select id,name,birthday,email from myusers”;
5、遍历结果集
ResultSet rs=new ResultSet();
rs=st.executeQuery(sql)
While(rs.next()){
System.out.print(rs.getInt("id"));
System.out.print("\t"+rs.getString("name"));
System.out.print("\t"+rs.getDate("birthday"));
System.out.print("\t"+rs.getString("password"));System.out.println(rs.getString("email"));
}
6、释放资源(最好写在finally里面)
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
三、程序详解
1、DriverManager
Jdbc程序中的DriverManager用于加载驱动,并创建与数据库的链接,这个API的常用方法:
DriverManager.registerDriver(new Driver()),注意:在实际开发中,并不推荐采用这个方法注册驱动。查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
推荐方式:Class.forName(“com.mysql.jdbc.Driver”);采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要import驱动的API,这样可使程序不依赖具体的驱动,使程序的灵活性更高。
DriverManager.getConnection(url, user, password),根据url获取数据库的链接。
2、数据库URL
jdbc:mysql:[]//localhost:3306/test ?参数名:参数值
3、Connection
Jdbc程序中的Connection,它用于代表数据库的链接,Collection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法:
createStatement():创建向数据库发送sql的statement对象。
prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象。
prepareCall(sql):创建执行存储过程的callableStatement对象。
setAutoCommit(boolean autoCommit):设置事务是否自动提交。
commit() :在链接上提交事务。
rollback() :在此链接上回滚事务。
4、Statement
Jdbc程序中的Statement对象用于向数据库发送SQL语句, Statement对象常用方法:
execute(String sql):用于向数据库发送任意sql语句
executeQuery(String sql) :只能向数据发送查询语句。
executeUpdate(String sql):只能向数据库发送insert、update或delete语句
addBatch(String sql) :把多条sql语句放到一个批处理中。
executeBatch():向数据库发送一批sql语句执行。
5、ResultSet
Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。
ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:
获取任意类型的数据
getObject(int index)
getObject(string columnName)
获取指定类型的数据,例如:
getString(int index)
getString(String columnName)
提问:数据库中列的类型是varchar,获取该列的数据调用什么方法?Int类型呢?bigInt类型呢?Boolean类型?
ResultSet还提供了对结果集进行滚动的方法:
next():移动到下一行
Previous():移动到前一行
absolute(int row):移动到指定行
beforeFirst():移动resultSet的最前面。
afterLast() :移动到resultSet的最后面。
6、释放资源
Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。
特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
四、使用JDBC处理大数据
在实际开发中,程序需要把大文本或二进制数据保存到数据库。
1、基本概念:大数据也称之为LOB(Large Objects),LOB又分为:clob:用于储存文本(Text)和blob:用于存储二进制数据,例如图像、声音、二进制文等。
2、对Mysql而言只有blob,而没有clob,mysql存储大文本采用的是Text,Text和blob分别又分为:
TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT
TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB
3、(1)对于MySQL中的Text类型,可调用如下方法设置:
PreparedStatement.setCharacterStream(index,reader, length);
//注意length长度须设置,并且设置为int型
(2)对MySQL中的Text类型,可调用如下方法获取:
reader = resultSet. getCharacterStream(i);
reader = resultSet.getClob(i).getCharacterStream();
string s = resultSet.getString(i);
(3)对于MySQL中的BLOB类型,可调用如下方法设置:
PreparedStatement.setBinaryStream(i,inputStream, length);
(4)对MySQL中的BLOB类型,可调用如下方法获取:
nputStream in = resultSet.getBinaryStream(i);
InputStream in = resultSet.getBlob(i).getBinaryStream();
五、使用JDBC进行批处理
当需要向数据库发送一批sql语句执行时,应避免向数据库一条条的发送执行,而采用JDBC的批处理机制,以提升执行效率
1、实现批处理有两种方式,第一种方式:
Statement.addBatch(sql) list
执行批处理SQL语句
executeBatch()方法:执行批处理命令
clearBatch()方法:清楚批处理命令
Connection con= null;
Statement st = null;
ResultSet rs = null;
try {
conn = DBManagerDemo.getConnection();
String sql1 = "insert into myusers(name,password)
values('kkk','123')";
String sql2 = "update myusers set password='123456' where id=3";
st = conn.createStatement();
st.addBatch(sql1); //把SQL语句加入到批命令中
st.addBatch(sql2); //把SQL语句加入到批命令中
st.executeBatch();
} finally{
DBManagerDemo.free(conn, st, rs);
}
2、第二种方式:
PreparedStatement.addBatch();
conn = DBManagerDemo.getConnection();
String sql = "insert into myusers(name,password) values(?,?)";
st = conn.prepareStatement(sql);
for(int i=0;i<50000;i++){
st.setString(1, "aaa" + i);
st.setString(2, "123" + i);
st.addBatch();
if(i%1000==0){
st.executeBatch();
st.clearBatch();
}
}
st.executeBatch();
六:获取数据库自动生成的主键
Connection con = DBManagerDemo.getConnection();
String sql = "insert into myusers(name,password)
values('abc','123')";
PreparedStatement st = con.
prepareStatement(sql,Statement.RETURN_GENERATED_KEYS );
st.executeUpdate();
ResultSet rs = st.getGeneratedKeys(); //得到插入行的主键
if(rs.next())
System.out.println(rs.getObject(1));
七、使用JDBC调用存储过程
1、在mysql中编写存储过程
得到CallableStatement,并调用存储过程:
CallableStatement cs = con.prepareCall("{call 创建的存储过程名(?, ?)}");
设置参数,注册返回值,得到输出
cs.setString(1, "abcdefg");
cs.registerOutParameter(2, Types.VARCHAR);
cs.execute();
System.out.println(cs.getString(2));
八、事物
事物的概念:事物指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。
例如:A--B转账,对应于如下两条sql语句
Update from account set money=money+100 where name=’b’;
Update from account set money=money-100 where name=’a’;
步骤:
1、数据库开启事务命令
(1)、start transaction 开启事务
Connection.setAutoCommit(false);
(2)、Rollback 回滚事务
Connection.rollback();
(3)、Commit 提交事务
Connection.commit();
九、事务的特性(ACID)
1、(1)原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
(2)、一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
(3)、隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
(4)、持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
2、多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。
3、如果不考虑隔离性,可能会引发如下问题:
(1)、脏读:
指一个事务读取了另外一个事务未提交的数据。
这是非常危险的,假设A向B转帐100元,对应sql语句如下所示
1.update account set money=money+100 while name=‘b’;
2.update account set money=money-100 while name=‘a’;
当第1条sql执行完,第2条还没执行(A未提交时),如果此时B查询自己的帐户,就会发现自己多了100元钱。如果A等B走后再回滚,B就会损失100元。
(2)、不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。
例如银行想查询A帐户余额,第一次查询A帐户为200元,此时A向帐户存了100元并提交了,银行接着又进行了一次查询,此时A帐户为300元了。银行两次查询不一致,可能就会很困惑,不知道哪次查询是准的。
和脏读的区别是,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。
很多人认为这种情况就对了,无须困惑,当然是后面的为准。我们可以考虑这样一种情况,比如银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个事务中针对输出的目的地,进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了。
(3)、虚读(幻读)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
如丙存款100元未提交,这时银行做报表统计account表中所有用户的总额为500元,然后丙提交了,这时银行再统计发现帐户为600元了,造成虚读同样会使银行不知所措,到底以哪个为准。