JDBC:数据库连接, 通过接口实现不同数据库之间的切换, 面向接口编程
JDBC驱动程序将JDBC调用映射成特定的数据库调用
驱动类型:
1.JDBC驱动:JDBC-ODBC桥,最早的实现方式,将JDBC API映射到ODBC API,Java8中已删除
2.直接将JDBC API映射成数据库特定的客户端API,次驱动包含特定数据库的本地代码,用于访问特定数据库的客户端
3.支持3层结构的JDBC访问方式,用于Applet,通过Applet访问数据库
4.直接与数据库实例交互,使用数据库底层协议
JDBC用法:
DriverManager: 管理JDBC驱动服务类, 用于获取Connection对象; 包含静态方法: synchronized Connection getConnection(String url,String user,String pass) throws SQL Exception
Connection(接口):连接数据库, 以下方法抛出SQLException
常用方法:Statement createStatement()//返回一个Statement对象
PreparedStatement prepareStatement(String sql)//返回预编译的Statement对象(将sql交给数据库预编译)
CallableStatement prepareCall(String sql)//返回CallableStatement对象,用于调用储存
PrepareStatement,CallableStatement是Statement子类
控制事务的方法:
Savepoint setSavepoint()//创建保存点
Savepoint setSavepoint(Stiring name)//指定名字创建
void setTransactionIsolation(int level)//设置事务隔离级别
void rollback()//回滚事务
void rollback(Savepoint savepoint)//将事务回滚到指定保存点
void setAutoCommit(bollean autoCommit)//关闭自动提交,打开事务
void commit()//提交事务
void setSchema(String schema)//设置数据库Schema, getSchema()//获取Schema
Statement:执行SQL语句工具类,可用于执行DDL,DCL,DML
ResultSet executeQuery(String sql)//只执行查询语句
int executeUpdate(String sql)//执行DML/DDL语句,返回受影响的行数/0
boolean excute(String sql)//执行任何SQL语句,执行第一个结果返回Result,返回true,其余为false
PreparedStatement: 预编译Statement对象,为Statement的子接口,使用PreparedStatement执行SQL语句无需多次传SQL语句,只需传对应参数
相比于Statement多增加了void setXxx(int parameterIndex,Xxx value)//传入值根据索引位置传给指定SQL指定位置的参数
具有executeUpdate, executeQuery, execute方法,无需接收SQL字符串,只需传参数
ResultSet: 结果集对象(包含查询结果的方法), 通过索引或列名获取列数据
void close()//释放ResultSet对象
boolean absolute(int row)//将结果集的记录指针移动到row行,row为负,移动到倒数row行, 指向有效记录时返回true
void beforeFirst()//将记录指针移动到起始位置的前一行
boolean first()//指针移动到首行,有效记录返回true
boolean previous()/next()//移动到上/下一行
boolean last()//最后一行
void afterLast()//最后一行之后
当移动到指定行,使用getXxx(int columnIndex)/getXxx(columnLabel)获取当前行列指定值
JDBC编程步骤:
1.加载驱动使用Class类的静态方法forName(), 加载MySQL驱动: Class.forName(“com.mysql.jdbc.Driver”);
2.通过DriverManager获取数据库连接: DriverManager.getConnection(String url,String user,String pass) 注:url写法固定,mysql: jdbc:mysql://hostname:port/databasename
3.通过Connection对象创建Statement对象: createStatement()/prepareStatement(String sql)/prepareCall(String sql)
4.使用Statement执行sql语句:execute()/executeUpdate()/executeQuery()
5.操作结果集: executeQuery()返回ResultSet对象,内部保存了SQL语句查询结果,使用ResultSet中的方法对内部结果进行查看
6.回收数据库资源: ResultSet, Statement, Connection
使用executeLargeUpdate执行DDL/DML 使用方式与executeUpdate一致
使用execute执行SQL语句: 通常情况不使用; 返回值为boolean类型(判断是否执行SQL语句)例: boolean hasResult=st.execute(sql);//使用ResultSet rs=st.getResultSet()获取返回的Result对象, 使用getUpdateCount(),获取Statement()执行DML语句影响的记录行数
管理结果集
ResultSet默认的记录指针移动方式(next()), 如果需要改变记录指针的移动方式需要在创建Statement/PreparedStatement对象传入参数:
resultSetType:
1.ResultSet.TYPE_SCROLL_INSENSITIVE//常量可控制记录指针自由移动,底层数据改变不影响ResultSet内容
2.ResultSet.TYPE_SCROLL_SENSITIVE//同上,但底层数据改变会影响ResultSet的内容
上述两者的区别在于数据库驱动
resultSetConcurrency:
1.控制ResultSet的并发类型
2.执行完executeQuery后返回的ResultSet对象使用updateXxx(int columnIndex,Xxx value)可用于更新数据库指定位置的数据(更新结果集必须满足:所选的数据必须来自同一个表,选出的数据中必须包含主键列), 使用updateRow()提交修改
注: Java8提供updateObject(String columnLable/int columnIndex,Object x,SQLtype targetSQLType);来直接修改记录指针所指向的记录
1.ResultSet.CONCUR_READ_ONLY:只读的并发模式(默认)
2.ResultSet.CONCUR_UPDATABLE:可更新的并发模式
例: PrepareStatement pstm=coon.PrepareStatement(sql,Result.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet rs=pstm.executeQuery();
rs.last();int rowCount=rs.getRow();
for(int i=rowCount;i>0;i–){
rs.absolute(i); rs.updateString(2,“学生名”+i);
rs.updateRow();//提交修改; 从后的行的位置将每行的student的名字做修改
}
执行execute/executeQuery/executeUpdate将会返回ResultSet对象(采用移动记录指针查看修改后的效果, 条件是在知道表结构,采用rs.next(),rs.getXxx()查看)
PreparedStatement执行SQL(需要反复执行)
使用占位符"?“放置到合适的位置, Statement不允许使用占位符”?", 出现PrepareStatement作为Statement的子接口
例:PreparedStatement ps=conn.preparedStatement(“insert into myJava_test (test_name)values”+ “(?)”);
PreparedStatement可用于防止SQL注入
举个例子: 将用户登录的账号或密码进行拼接作为去数据库查找的数据, 一些特定的字符串会导致, 不用账号密码也能登陆, 比如:‘or true or’,
PreparedStatement相比于Statemnet可以做到: 预编译SQL语句,无需SQL拼接(防止SQL注入)
使用CallableStatement调用存储过程(也就所谓设计一个函数,然后调用完成一系列操作)
例: 格式如下
delimiter//
create procedure add_proName(a int,b int, out sum int)#create procedure为创建关键字,out表示输入
begin set sum=a+b;
end;
//
#将结束符改为("//"),使得在创建储存过程中可以使用分号,在完成存储函数的定义(使用delimiter)后, 使用call add_proName(1,2,@sum);调用这个函数,@sum表示将函数结果放到形参中; 具体不做阐述
调用储存过程使用CallableStatement, 通过Connection的prepareCall()方法创建CallableStatement对象,创建对象的过程中传入SQL语句: 格式如下----{call add_proName(?,?,?)}//使用通配符"?"
例: CallableStatement csmt=conn.prepareCall("{Call add_proName(?,?,?)}");//完成调用操作
csmt.setXxx();//设置传入参数 csmt.registerOutParameter(3,Types.INTEGER)//注册参数 上述操作完成后使用csmt.execute();//执行SQL语句
处理Blob类型数据(Blob表示二进制长对象,如图片/音视频)
使用PreparedStatement中的对象的方法:将图片等插入数据库:psmt.setBinaryStream(int parameterIndex,InputStream is,int length)//传入二进制输入流
psmt.executeUpdate();
从ResultSet中提取Blob数据:Blob blob=rs.getBlob(int columnIndex)
使用ResultSetMetaData查看结果集
ResultSet对象包含getMetaData(),用于返回ResultSet的ResultSetMetaData对象
int i=rsmd.getColumnCount()//返回ResultSet的列数量
String s=rsmd.getColunName(int column)//返回指定列名
int i=getColumnType(int column)//返回索引列类型
使用ResultSetMetaData会造成系统开销
事务处理(多条SQL要么全部执行,要么放弃执行;具有原子性,一致性,隔离性,持续性)
事务提交: 显式提交(commit),自动提交(DDL/DCL DML语句会导致事务立即被处理)
事务提交的过程中会出现某个操作失败,需要rollback事务(刚才执行的操作全部失效): 分为显式回滚(rollback),自动回滚(系统错误自动退出);
MySQL默认关闭事务,在DML语句中需要添加:set autocommit=0 开启事务(DML语句不会立马生效,需要使用commit显式提交或者运行DDL/DCL语句),1表示自动提交
设置事务只会对当前的命令行窗口有效,MySQL使用start transaction或者begin来执行一次临时的事务
例: begin; insert into studentTable values(null,‘A’,1); insert into studentTable values(null,‘B’,2); select * from studenttable;#插入记录成功 rollback();上述操作全部失效
savepoint a;#设置事务的中间点让事务回滚到中间点位置
rollback to a;
注: 回滚到指定位置并不会结束当前事务
JDBC事务支持
conn.setAutoCommit(false);//开启事务
stm.executeUpdate(…);stm.executeUpdate(…);stm.executeUpdate(…);
conn.commit();//提交事务
conn.rollback();//回滚事务,当SQL语句出现异常,将会自动回滚事务
Savepoint sp=coon.setSavepoint();//设置断点
conn.rollback(Savepoint sp);//回滚到指定断点
使用DatabasesMetaDate分析数据库信息
DatabaseMetaData dmd=conn.getMetaData();
例:ResultSet rs=dmd.getTableTypes();//通常DatabaseMetaData的方法返回ResultSet对象
使用连接池管理连接(创建足够多的数据库连接,避免应用程序多次重新打开数据库连接,提高效率)
DBCP连接池:Apache旗下, Tomcat采用此连接池,需下载到apache网站下载commons-pool.zip,commons-dbcp.zip,可与应用服务器整合使用,也可以应用程序独立使用
BasicDataSource ds=new BasicDataSource();//创建数据源对象
ds.setDriverClassName(“com.mysql.jdbc.Driver”);//连接驱动
ds.setUrl(“jdbc:mysql://localhost:3306/test”);
ds.setUsername(“root”);ds.setPassword(“12345”);
ds.setInitialSize(5);//设置初始连接数
ds.setMaxActive(20);//最多为20个活动连接
ds.setMinIdle(2);//最少2个空闲连接
Connection conn=ds.getConnection();//连接数据库
conn.close();//释放链接
C3P0连接池…; 与DBCP一致自行百度