Java核心编程七:数据库访问

来源:互联网 发布:程序员思维,出门买菜 编辑:程序博客网 时间:2024/05/08 00:18
1 JDBC设计

JDBC提供两套接口,应用程序开发者使用JDBC API,而数据库提供商使用JDBC驱动API。

2 JDBC编程概念
与SQL相关的类都包含在java.sql和javax.sql中。
2.1 设置驱动路径
不同的数据库需要下载相应的驱动jar包安装到系统中,然后设置系统CLASSPATH或运行时classpath参数,使得驱动在运行时可加载。
2.2 驱动注册
驱动必须通过DriverManager进行注册才可以挂到系统里。
System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver");
Class.forName("com.mysql.jdbc.Driver");

2.3 数据库连接
java采用类似url的方式表示数据库的相关信息,不同的数据库驱动支持不同。
针对MySQL,其格式为:jdbc:mysql://ip:port/dbname

2.4 创建连接并执行

String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/cd-collection-db";
Class.forName(driver);
Connection con = DriverManager.getConnection(url,"user","passwd");
if(!con.isClosed())
{
System.out.println("Succeeded connecting to Database");
}
Statement stat = con.createStatement();
stat.execute("SELECT * FROM cds");
ResultSet rs = stat.getResultSet();
while(rs.next())
{
System.out.printf("%d,%s\n",rs.getInt("id"),rs.getString("titel"));
}

rs.close();
con.close();

通常建议将driver,url,user,passwd等信息写在配置文件中,在运行时加载,而非写在代码中。

2.5 类型处理

处理数据库的常用API如下:
DriverManagement类:
static Connection getConnection(url,user,passwd)

Connection类:
Statement createStatement()
PreparedStatement prepareStatement(String sql)
close()

Statement类:
bool exceut()
ResultSet exceutQuery(sql)
int exceutUpdate(sql)
int getUpdateCount()
ResultSet getResultSet()
close()

PreparedStatement类:
setXxx(int idx,Xxx x) Xxx为数据类型如int,String,Date等
ResultSet executeQuery()
int executeUpdate()
void clearParameters() 

ResultSet类
next()
getXXX(int)   按位置返回结果
getXXX(String) 按名称返回结果
close()

通常要在使用完之后立即调用close()来释放资源,不要等待资源回收去做这个事情。

一般来说,最好使用PreparedStatement来实现数据库的操作,以实现较高的性能,并简化使用。

3 结果集的滚动和更新
在JDK3以后,ResultSet的功能进行了很大的增加,包含数据自动更新到数据库,前向遍历等。
Connection类:
Statement createStatement(int type,int concurrency)
PreparedStatement prepareStatement(String sql,int type,int cc)

type:ResultSet接口中常量,用于指定结果集的遍历方向及对数据库变更的敏感度
TYPE_FORWARD_ONLY,TYPE_SCROLL_INSENSITIVE,TYPE_SCROLL_SENSITIVE

Concurrency:RS接口中常量,用于指定结果的并发及是否支持写回到数据库
CONCUR_READ_ONLY,CONCUR_UPDATABLE
并非所有返回的结果都是可更新的,简单查询返回的结果方可进行更新,是否可更新可通过RS相应接口查询。

ResultSet类:
getType() 返回RS的TYPE类型
getConcurrency() 返回更新数据库的类型
bool previous() 如果前向遍历成功则执行并返回true
int getRow()  返回当前行的位置,行编号从1开始
bool relative(int offset)  移动offset个距离 
... 各种定位函数,及位置判断函数
void moveToInsertRow() 在RS中设置一个插入行
void moveToCurrentRow() 定位到刚插入行的位置
void insertRow()  将插入行保存到RS及数据库中
void deleteRow()  将当前行从RS和数据库中删除
void updateRow()  更新当前行到RS和数据库中
void updateXXX(int column, XXX data)  更新RS中当前行的指定列
void updateXXX(string name,XXX data)
void cancelRowUpdate()

DatabaseMetaData类:
bool supportsResultSetType(int type)
bool supportsResultSetConcurrency(int type,int cc)

4 元数据
对于已经数据库结构的情况下,了解元数据没有太大意义,但如果开发数据库工具,则比较有用。例如SQLUI客户端中浏览数据及表的定义及字段属性等。其中提供了大量的接口都是为了获取并操作元数据的。
有三类元数据:数据库元数据、结果集的元数据、预备语句的元数据。
Connection类:
DatabaseMetaData getMetaData() 

DatabaseMetaData类:
ResultSet getTables(String db,String dbPattern,String tableNamePattern,String types[]);
type表示表的类型,如TABLE,VIEW等,若为null,则返回所有类型表。

ResultSet类:
ResultSetMetaData getMetaData()

ResultSetMetaData类:
int getColumnCount() 列个数
int getColumnDisplaySize(int) 返回指定列的最大宽度
String getColumnLabel(int) 返回结果中指定列的名称
String getColumnName(int) 返回指定列的数据库列名

5 行集
ResultSet的问题是必须一直持有数据库连接,为了解决这个问题,采用RowSet对结果进行缓存,无需一直保持连接。RowSet定义在javax.sql包中,并继承了ResultSet所有接口。这个rowset都只是接口,而实现均为在名捕加Impl进行命名。以CachedRowSet为例进行说明。

当执行命令时,只需要打开数据库连接,执行查询,将结果放入选集,然后关闭连接。
我们也可以修改缓存行的数据,最后发起请求,将缓存结果再次存入数据库,此时rowset会连接到数据库并进行数据的更新。
CachedRowSet rowset = new CachedRowSetImpl();
rowset.populate(rs);
conn.close();
当然也可以直接通过RowSet进行数据库操作:
void setUrl(String)
void setUsername(String)
void setPassword(String)
void setCommand(string)
void execute()
void populate(ResultSet rs)
void acceptChanges()
需要注意的是,如果提交数据时,数据库中的数据已经更新,会导致提交失败,并报出SyncProveder异常。内部应该采用了MVVC实现了悲观离线锁。

6 事务
默认连接上为自动提交的,可以关闭自动提交,当在statement上执行后进行事务操作。
Connection类:
setAutoCommit(bool)
commit()
rollback()
6.1 保存点
如果事务执行过长,失败回退代价较高,可以使用SavePoint来实现事务分段,回滚时只回滚到指定保存点。
SavePoint svpt =conn.setSavepoint();
...
con.rollback(svpt);
con.releaseSavepoint();
6.2 批处理
state.addBatch(sql)
...//addBatch more
state.executeBatch()
如果在批处理中使用事务,则事务会将批处理的整体做为一个事务,没有办法进行分段。

7 高级连接管理
主要是一些JNDI的接口,用于获取数据库的相关配置信息。

8 LDAP概念
如果应用的数据是基于树形的,则可以使用LDAP协议。
JAVA在包javax.naming包中实现了相关的接口支持。

0 0