文章目录
使用RowSet对象
RowSet对象以一种比ResultSet更灵活,更易于使用的方式保存表格数据
- RowSet对象可以做什么
- 充当KavaBeans对象
- Properties
- 所有RowSet对象都有属性
- JavaBeans通知机制
- 对于所有RowSet对象,光标移动、更新、插入或删除行、更改所有RowSet内容都会触发事件通知
- Properties
- 滚动性和可更新性
- 充当KavaBeans对象
- 对象的种类
- 连接的RowSet对象
- 使用jdbc驱动程序做出一个关系型数据库的连接,并保持其在整个生命跨度连接
- JDBCRowSet对象,仅有的一个连接RowSet对象,使原本不可更新和滚动的ResultSet对象可更新和可滚动
- 作为JavaBeans,在GUI工具中使用JdbcRowSet对象选择JDBC驱动程序
- 断开连接的RoeSet对象
- 断开连接的RowSet对象具有连接对象的所有功能,此外,还具有对断开连接的RowSet对象可用的附加功能
- CacheRowSet对象具有JdbcRowSet对象的所有功能
- 获取数据源的连接并执行查询
- 从结果ResultSet对象中读取数据,并使用该数据填充自身
- 断开连接时处理数据并对其进行更改
- 重新连接到数据源以将更改写回到它
- 检查与数据源的冲突并解决这些冲突
- WebRowSet对象具有CacheRowSet对象的所有功能
- 将自己编写为XML对象
- 阅读描述WebRowSet对象的XML文档
- JoinRowSet对象具有WebRowSet的所有功能
- 形式等效于SQL JOIN而不必连接到数据源
- FilterredRowSet对象具有WebRowSet对象的所有功能
- 应用过滤条件,以便仅可见选定的数据。等效于在RowSet不适用查询语言或连接到数据源的情况下对对象执行查询
- 连接的RowSet对象
使用JdbcRowSet对象
是一种增强的ResultSet对象,除了维护和其数据源的连接,它还具有一组属性和一个侦听器通知机制,这些机制使它成为JavaBeans组件
- 创建JbdcRowSet对象
- 创建对象方式
- 通过使用带ResultSet对象的引用实现构造函数
- 通过使用带Connection对象的引用实现构造函数
- 通过使用参考实现的默认构造函数
- 通过使用RowSetFactory实例,该实例从RowSetProvider创建
- 传递ResultSet对象
- 产生ResultSet对象传递给JdbcRowSetImpl构造函数
- 传递给JdbcRowSetImpl构造函数的Result对象必须是可滚动的
stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); rs = stmt.executeQuery("select * from COFFEES"); jdbcRs = new JdbcRowSetImpl(rs);
- 传递Connection对象
除非特定指定,否则JdbcRowSet所有其他RowSet对象都是可滚动和可更新的jdbcRs = new JdbcRowSetImpl(con); jdbcRs.setCommand("select * from COFFEES"); jdbcRs.execute();
- 使用默认构造函数
public void createJdbcRowSet(String username, String password) { jdbcRs = new JdbcRowSetImpl(); jdbcRs.setCommand("select * from COFFEES"); jdbcRs.setUrl("jdbc:myDriver:myAttribute"); jdbcRs.setUsername(username); jdbcRs.setPassword(password); jdbcRs.execute(); // ... }
- 使用RowSetFactory接口
- 使用RowSetFactory创建JdbcRowSet对象
public void createJdbcRowSetWithRowSetFactory( String username, String password) throws SQLException { RowSetFactory myRowSetFactory = null; JdbcRowSet jdbcRs = null; ResultSet rs = null; Statement stmt = null; try { // 默认实现创建RowSetProvider对象 myRowSetFactory = RowSetProvider.newFactory(); // 创建JdbcRowSet对象并配置其数据库连接属性 jdbcRs = myRowSetFactory.createJdbcRowSet(); jdbcRs.setUrl("jdbc:myDriver:myAttribute"); jdbcRs.setUsername(username); jdbcRs.setPassword(password); jdbcRs.setCommand("select * from COFFEES"); jdbcRs.execute(); // ... } }
- RowSetFactory接口包含不同类型的实现的方法
- createCachedRowSet
- createFilteredRowSet
- createJdbcRowSet
- createWebRowset
- 使用RowSetFactory创建JdbcRowSet对象
- 创建对象方式
- 默认得JDBCRowSet对象
- 使用默认构造函数创建对象时,新JdbcRowSet对象将具有以下属性:
- type:(ResultSet的TYPE_SCROLL_INSENSITTIVE具有可滚动的光标)
- concurrency:(ResultSet.CONCUR_UPDATABLE可以更新)
- escapeProcessing:(true,驱动程序进行转义处理;启用转义处理时,驱动程序将扫描任何转义语法并将其转换为特定数据库可以理解的代码)
- maxRows:(0,行数没有限制)
- maxFieldSize:(0,上一列值中的字节的数量没有限制,仅适用于该商店字符类型列的值)
- queryTimeOut:(0,执行查询所需的时间没有时间限制)
- showDeleted:(false删除的行不可见)
- transactionIsolation:(Connection.TRANSACTION_READ_COMMITTED仅读取已提交的数据)
- typeMap:(null,Connection对象与使用的RowSet对象关联的类型映射为null)
- 使用默认构造函数创建对象时,新JdbcRowSet对象将具有以下属性:
- 设定属性
- 默认JdbcRowSet对象在创建新对象时有部分默认得属性
- 用于保存获得与数据库连接信息的属性
- username:用户为获得访问权限而提供给数据库的名称
- password:用户的数据库密码
- url:用户要连接到的数据库的JDBC URL
- datasourceName:用于检索DataSource已在JNDI命令服务中注册的对象的名称
- 首选DataSource对象建立连接
- 使用DriverManager机制获取连接
- 必须设置command属性确定JdbcRowSet对象保存哪些数据的查询
//该查询产生一个包含表中所有数据的ResultSet对象 jdbcRs.setCommand(“ select * from COFFEES”);
- 设置建立连接必须的command属性后,调用excute方法为对象填充数据
jdbcRs.execute();
- 使用你分配的Url、username、password的值创建与数据库的连接
- 执行在command属性中设置的查询
- 将结果ResultSet对象读取到jdbcRs对象中
- 使用JdbcRowSet对象
- 默认情况下,JdbcRowSet对象是可滚动和可更新的
- 导航JdbcRowSet对象
- 只能使用next方法向前移动光标并且可滚动的ResultSet对象,可以从第一行仅向前移动光标到最后一行。默认得JdbcSet对象可以使用ResultSet接口中定义的所有光标和移动方法
- JdbcRowSet对象可以调用next方法,也可以调用任何其他ResultSet光标移动方法。如:
jdbcRs.absolute(4); jdbcRs.previous();
- 更新列值
//将光标移动到第三行,并将该列的值更改,然后更新数据库 jdbcRs.absolute(3); jdbcRs.updateFloat(“ PRICE”,10.99f); jdbcRs.updateRow();
- 插入行
//将光标移到插入行,使用update方法设置列值,调用interRow插入 jdbcRs.moveToInsertRow(); jdbcRs.updateString("COF_NAME", "HouseBlend"); jdbcRs.updateInt("SUP_ID", 49); jdbcRs.updateFloat("PRICE", 7.99f); jdbcRs.updateInt("SALES", 0); jdbcRs.updateInt("TOTAL", 0); jdbcRs.insertRow(); jdbcRs.moveToInsertRow(); jdbcRs.updateString("COF_NAME", "HouseDecaf"); jdbcRs.updateInt("SUP_ID", 49); jdbcRs.updateFloat("PRICE", 8.99f); jdbcRs.updateInt("SALES", 0); jdbcRs.updateInt("TOTAL", 0); jdbcRs.insertRow();
- 删除行
//将光标移到最后一行,删除最后一行 jdbcRs.last(); jdbcRs.deleteRow();
使用CachedRowSetObjects
将数据储存在内存中,可以对自己的数据进行操作,而不是对数据库中存储的数据进行操作。CachedRowSet接口是所有断开RowSet对象接口的超接口
- 设置CachedRowSet对象
- 创建CachedRowSet对象
- 使用默认构造函数
CachedRowSet crs = new CachedRowSetImpl();
- 使用RowSetFactory从RowSetProvider类创建实例
- 使用默认构造函数
- 使用默认构造函数
CachedRowSet crs = new CachedRowSetImpl();
- 设置CacheRowSet属性
- 数据库连接信息:username、password、url、datdasourceName
public void setConnectionProperties( String username, String password) { crs.setUsername(username); crs.setPassword(password); crs.setUrl("jdbc:mySubprotocol:mySubname"); // ...
- 设置command属性
crs.setCommand("select * from MERCH_INVENTORY");
- 设置键列,需要两列或更多列唯一标识一行
int [] keys = {1}; crs.setKeyColumns(keys);
- 数据库连接信息:username、password、url、datdasourceName
- 设置CacheRowSet属性
- 创建CachedRowSet对象
- 填充CachedRowSet对象
// crs是通过command属性中执行查询而产生的resultset对象中的数据 crs.execute();
- 每个断开连接的RowSet对象都有一个分配给它的SyncProvider对象,而改SyncProvider对象正是提供RowSet对象的读取器(RowSetReader对象)的对象
- Reader做什么
- 当程序调用execute方法时,断开连接的RowSet对象的读取器在后台工作,用数据填充RowSet对象。
- 新创建的CacheRowSet对象为连接到s数据源,因此必须获得与该数据源的连接才能从中获取数据。
- 默认SyncProvider对象的实现提供了一个读取器,该读取器通过使用用户名、密码以及JDBC URL或数据源名称设置的值来获得连接
- 然后,reader executer执行命令查询集。它读取查询产生的CachedRowSet对象中的数据,并使用该数据填充对象
- 最后,Reader 关闭连接
- 更新CachedRowSet对象
- 更新列值
- 更新CachedRowSet对象中的数据与更新JdbcRowSet对象中的数据相同
while (crs.next()) { System.out.println( "Found item " + crs.getInt("ITEM_ID") + ": " + crs.getString("ITEM_NAME")); if (crs.getInt("ITEM_ID") == 1235) { int currentQuantity = crs.getInt("QUAN") + 1; System.out.println("Updating quantity to " + currentQuantity); crs.updateInt("QUAN", currentQuantity + 1); crs.updateRow(); // Synchronizing the row // back to the DB crs.acceptChanges(con); }
- 更新CachedRowSet对象中的数据与更新JdbcRowSet对象中的数据相同
- 插入和删除行
- 在CachedRowSet对象中插入和删除行的代码与针对JdbcRowSet对象的代码相同
crs.moveToInsertRow(); crs.updateInt("ITEM_ID", newItemId); crs.updateString("ITEM_NAME", "TableCloth"); crs.updateInt("SUP_ID", 927); crs.updateInt("QUAN", 14); Calendar timeStamp; timeStamp = new GregorianCalendar(); timeStamp.set(2006, 4, 1); crs.updateTimestamp( "DATE_VAL", new Timestamp(timeStamp.getTimeInMillis())); crs.insertRow(); crs.moveToCurrentRow();
//删除特定行 while (crs.next()) { if (crs.getInt("ITEM_ID") == 12345) { crs.deleteRow(); break; } }
- 在CachedRowSet对象中插入和删除行的代码与针对JdbcRowSet对象的代码相同
- 更新数据
- 主要区别
- JdbcRowSet对象针对数据源的操作同时更新对象和数据源
- CachedRowSet对象在断开连接的额情况下,操作只更新储存在对象内存中的数据,但不会影响数据源
//调用此方法更新数据源 crs.acceptChanges();
- 主要区别
- 更新列值
- writer做什么
- execu方法将其工作委托给RowSet对象的reader,acceptChanges方法将其任务委托给RowSet对象的writer
- 在后台,writer打开与数据库的连接,使用对RowSet对象所做的更改来更新数据库,然后关闭连接
- 使用默认实现
- 可能会发生冲突:指另一方已更新数据库中与RowSet对象中更新的值相对应的情况,哪个值应该保存在数据库中
- 两方面解决
- writer不检查冲突,将所有更改写入数据库
- writer通过设置数据库锁来防止其他人进行修改,从而确保不存在冲突
- crsd对象默认的writer是默认SyncProvider实现提供的RIOptimisticProvider。该对象实现使用乐观并发模型。该模型假定几乎没有冲突,因此不设置数据库锁。writer检查是否存在冲突,如果没有,则将对crs对象所做的更改写入数据库,然后将这些更改变为持久性,如果存在,默认不将RowSet值写入数据库
- 使用SyncResolver对象
- 使用SyncResolver解决其他情况下存在的冲突
- Writer完成查找冲突并找到一个或多个冲突,创建一个SyncResolver对象,该对象包含导致冲突的数据库值,然后acceptChanges方法抛出SyncProviderException对象,捕获该异常并使用SyncResolver检索该对象
try { crs.acceptChanges(); } catch (SyncProviderException spe) { //是复制RowSet对象的对象,仅包含导致冲突的数据库中的值,其他列值为null SyncResolver resolver = spe.getSyncResolver(); }
- Resolver对象遍历其行以查找不为null的值,然后将值定位在crs对象中相同位置并进行比较
try { crs.acceptChanges(); } catch (SyncProviderException spe) { SyncResolver resolver = spe.getSyncResolver(); // value in crs Object crsValue; // value in the SyncResolver object Object resolverValue; // value to be persistent Object resolvedValue; while (resolver.nextConflict()) { if (resolver.getStatus() == SyncResolver.UPDATE_ROW_CONFLICT) { int row = resolver.getRow(); crs.absolute(row); int colCount = crs.getMetaData().getColumnCount(); for (int j = 1; j <= colCount; j++) { if (resolver.getConflictValue(j) != null) { crsValue = crs.getObject(j); resolverValue = resolver.getConflictValue(j); // ... // compare crsValue and // resolverValue to // determine the value to be // persistent resolvedValue = crsValue; resolver.setResolvedValue( j, resolvedValue); } } } } }
- Notifying Listeners
- 成为JavaBeans组件意味着RowSet对象可以在发生某些事件时通知其他组件
- 设置监听器
- RowSet对象的监听器是从RowSetListenter接口中实现以下方法:
- cursorMoved:定义RowSet对象中光标移动时侦听器将执行的操作
- rowChanged:定义当前行的一个或多个列值已更改,已插入h或已删除行时侦听器将执行的操作
- rowSetChanged:定义在RowSet用新数据填充对象时监听器将执行的操作
// 添加监听 crs.addRowSetListener(bar); // 删除监听 crs.removeRowSetListener(bar);
- RowSet对象的监听器是从RowSetListenter接口中实现以下方法:
- 通知的工作方式
- 导致任何RowSet事件的方法都会自动通知所有注册的侦听器
使用JoinRowSet对象
当对象为连接到数据源时,JoinRowSet对象可以通过实现JOIN在RowSet对象之间创建SQL,节省了必须创建一个或多个连接的开销
- 创建JoinRowSet对象
JoinRowSet jrs = new JoinRowSetImpl();
- 添加RowSet对象
- 任何RowSet对象都可以添加到JoinRowSet对象,只要它可以是SQL JOIN的一部分
coffees = new CachedRowSetImpl(); coffees.setCommand("SELECT * FROM COFFEES"); coffees.setUsername(settings.userName); coffees.setPassword(settings.password); coffees.setUrl(settings.urlString); coffees.execute(); suppliers = new CachedRowSetImpl(); suppliers.setCommand("SELECT * FROM SUPPLIERS"); suppliers.setUsername(settings.userName); suppliers.setPassword(settings.password); suppliers.setUrl(settings.urlString); suppliers.execute();
- 任何RowSet对象都可以添加到JoinRowSet对象,只要它可以是SQL JOIN的一部分
- 管理Match Columns
- 添加到JoinRowSet对象中每个RowSet对象都必须具有一个基于JOIN的match列
- 设置RowSet对象的匹配列的方法
- 将match列传递给JoinRowSet中的addRowSet方法
jrs.addRowSet(coffees, 2);
System.out.println("Coffees bought from " + supplierName + ": "); while (jrs.next()) { if (jrs.getString("SUP_NAME").equals(supplierName)) { String coffeeName = jrs.getString(1); System.out.println(" " + coffeeName); } } //将产生输出: //从Acme,Inc.购买的咖啡: // 哥伦比亚 // Colombian_Decaf
- 将match列传递给JoinRowSet中的addRowSet方法
使用FilteredRowSet
FilteredRowSet对象仅显示适合设置的限制的数据行,提供了一种在断开连接RowSet对象执行筛选,而不必在数据源上执行查询
- 提供功能
- 根据设置的标准限制可见的行
- 选择可见的数据而无需连接到数据源
- 在Predicate对象中定义过滤条件
- 实现Predicate接口设置可见行的标准。初始化:
- 值必须落入范围的高端
- 值必须落入范围的下限
- 列的名称或列号,其值必须在上下边界设置的值得范围内
生命过滤器public class StateFilter implements Predicate { private int lo; private int hi; private String colName = null; private int colNumber = -1; public StateFilter(int lo, int hi, int colNumber) { this.lo = lo; this.hi = hi; this.colNumber = colNumber; } public StateFilter(int lo, int hi, String colName) { this.lo = lo; this.hi = hi; this.colName = colName; } public boolean evaluate(Object value, String columnName) { boolean evaluation = true; if (columnName.equalsIgnoreCase(this.colName)) { int columnValue = ((Integer)value).intValue(); if ((columnValue >= this.lo) && (columnValue <= this.hi)) { evaluation = true; } else { evaluation = false; } } return evaluation; } public boolean evaluate(Object value, int columnNumber) { boolean evaluation = true; if (this.colNumber == columnNumber) { int columnValue = ((Integer)value).intValue(); if ((columnValue >= this.lo) && (columnValue <= this.hi)) { evaluation = true; } else { evaluation = false; } } return evaluation; } public boolean evaluate(RowSet rs) { CachedRowSet frs = (CachedRowSet)rs; boolean evaluation = false; try { int columnValue = -1; if (this.colNumber > 0) { columnValue = frs.getInt(this.colNumber); } else if (this.colName != null) { columnValue = frs.getInt(this.colName); } else { return false; } if ((columnValue >= this.lo) && (columnValue <= this.hi)) { evaluation = true; } } catch (SQLException e) { JDBCTutorialUtilities.printSQLException(e); return false; } catch (NullPointerException npe) { System.err.println("NullPointerException caught"); return false; } return evaluation; } }
适用于多列的筛选器StateFilter myStateFilter = new StateFilter(10000, 10999, 1);
多列定义筛选条件public Filter2(Object [] lo,Object [] hi,Object [] colNumber){ this.lo = lo; this.hi = hi; this.colNumber = colNumber; }
public boolean evaluate(RowSet rs) { CachedRowSet crs = (CachedRowSet)rs; boolean bool1; boolean bool2; for (int i = 0; i < colNumber.length; i++) { if ((rs.getObject(colNumber[i] >= lo [i]) && (rs.getObject(colNumber[i] <= hi[i]) { bool1 = true; } else { bool2 = true; } if (bool2) { return false; } else { return true; } } }
- 实现Predicate接口设置可见行的标准。初始化:
- 创建FilteredRowSet对象
- 使用构造函数创建FilteredRowSet对象
FilteredRowSet frs = new FilteredRowSetImpl();
- FilteredRowSet是CachedRowSet、Joinable以及WebRowSet的子接口,因此具备各自的功能
- RowSetFactory类的实例RowSetProvider创建FilteredRowSet对象
- 必须使用来自table数据源的数据填充自身
//数据源信息 frs.setCommand(“ SELECT * FROM COFFEE_HOUSES”); frs.setUsername(settings.userName); frs.setPassword(settings.password); frs.setUrl(settings.urlString); //数据填充 frs.execute();
- 使用构造函数创建FilteredRowSet对象
- 创建和设置Predicate对象
- 创建Filter过滤器
StateFilter myStateFilter = new StateFilter(10000, 10999, 1);
- 设置过滤器
frs.setFilter(myStateFilter);
- 创建Filter过滤器
- 使用新的Predicate对象设置FilteredRowSet进行进一步数据过滤
- 多次叠加过滤器
public class CityFilter implements Predicate { private String[] cities; private String colName = null; private int colNumber = -1; public CityFilter(String[] citiesArg, String colNameArg) { this.cities = citiesArg; this.colNumber = -1; this.colName = colNameArg; } public CityFilter(String[] citiesArg, int colNumberArg) { this.cities = citiesArg; this.colNumber = colNumberArg; this.colName = null; } public boolean evaluate Object valueArg, String colNameArg) { if (colNameArg.equalsIgnoreCase(this.colName)) { for (int i = 0; i < this.cities.length; i++) { if (this.cities[i].equalsIgnoreCase((String)valueArg)) { return true; } } } return false; } public boolean evaluate(Object valueArg, int colNumberArg) { if (colNumberArg == this.colNumber) { for (int i = 0; i < this.cities.length; i++) { if (this.cities[i].equalsIgnoreCase((String)valueArg)) { return true; } } } return false; } public boolean evaluate(RowSet rs) { if (rs == null) return false; try { for (int i = 0; i < this.cities.length; i++) { String cityName = null; if (this.colNumber > 0) { cityName = (String)rs.getObject(this.colNumber); } else if (this.colName != null) { cityName = (String)rs.getObject(this.colName); } else { return false; } if (cityName.equalsIgnoreCase(cities[i])) { return true; } } } catch (SQLException e) { return false; } return false; } }
- 多次叠加过滤器
- 更新FilteredRowSet对象
- 前提是更改不违反当前有效的任何过滤条件
- 插入或更新行
frs.moveToInsertRow(); frs.updateInt("STORE_ID", 10101); frs.updateString("CITY", "SF"); frs.updateLong("COF_SALES", 0); frs.updateLong("MERCH_SALES", 0); frs.updateLong("TOTAL_SALES", 0); frs.insertRow(); frs.updateInt("STORE_ID", 33101); frs.updateString("CITY", "SF"); frs.updateLong("COF_SALES", 0); frs.updateLong("MERCH_SALES", 0); frs.updateLong("TOTAL_SALES", 0); frs.insertRow(); frs.moveToCurrentRow();
- 删除所有筛选器
frs.setFilter(null);
- 删除行
- 只能对可见的行进行删除操作
WebRowSet对象
WebRowSet对象除了提供CachedRowSet对象的所有功能,还可以写一个XML文档,也可以读取XML文档本身并转换为WebRowSet对象。XMl是不同企业之间可以通过其进行通信的语言,所以已成为Web服务通信的标准
- 创建和填充WebRowSet对象
- 使用默认构造函数创建
WebRowSet priceList = new WebRowSetImpl();
- 使用从RowSetProvider类创建的RowSetFactory实例创建WebRowSet对象
- 填充对象
public void getPriceList(String username, String password) { priceList.setCommand("SELECT COF_NAME, PRICE FROM COFFEES"); priceList.setURL("jdbc:mySubprotocol:myDatabase"); priceList.setUsername(username); priceList.setPassword(password); priceList.execute(); // ... }
- 使用默认构造函数创建
- 将WebRowSet对象写入和读取为XML
- 调用writeXml方法将WebRowSet对象写为XML文档
- 调用ReadXml方法将XML文档的内容读入WebRowSet对象
- writeXml方法
将RowSet对象数据写入到WebRowSet对象中,并将WebRowSet对象作为XML文档的写入流//通过outputStream传递,以字节单位写入 java.io.FileOutputStream oStream = new java.io.FileOutputStream("priceList.xml"); priceList.writeXml(oStream); //通过Writer传递,以字符写入 java.io.FileWriter writer = new java.io.FileWriter("priceList.xml"); priceList.writeXml(writer);
priceList.writeXml(rs, oStream); priceList.writeXml(rs, writer);
- readXml方法
将XML文档内容读取到WebRowSet对象中java.io.FileInputStream iStream = new java.io.FileInputStream("priceList.xml"); priceList.readXml(iStream); java.io.FileReader reader = new java.io.FileReader("priceList.xml"); priceList.readXml(reader);
WebRowSet recipient = new WebRowSetImpl(); java.io.FileReader reader = new java.io.FileReader("priceList.xml"); recipient.readXml(reader);
- XML文档内容
- 主要元素:Properties(属性)、Metadata(元数据)、Data(数据)
- Properties
<properties> <command> select COF_NAME, PRICE from COFFEES </command> <concurrency>1008</concurrency> <datasource><null/></datasource> <escape-processing>true</escape-processing> <fetch-direction>1000</fetch-direction> <fetch-size>0</fetch-size> <isolation-level>2</isolation-level> <key-columns> <column>1</column> </key-columns> <map> </map> <max-field-size>0</max-field-size> <max-rows>0</max-rows> <query-timeout>0</query-timeout> <read-only>true</read-only> <rowset-type> ResultSet.TYPE_SCROLL_INSENSITIVE </rowset-type> <show-deleted>false</show-deleted> <table-name>COFFEES</table-name> <url>jdbc:mysql://localhost:3306/testdb</url> <sync-provider> <sync-provider-name> com.sun.rowset.providers.RIOptimisticProvider </sync-provider-name> <sync-provider-vendor> Sun Microsystems Inc. </sync-provider-vendor> <sync-provider-version> 1.0 </sync-provider-version> <sync-provider-grade> 2 </sync-provider-grade> <data-source-lock>1</data-source-lock> </sync-provider> </properties>
- Metadata
从此元数据部分,您可以看到每行有两列。第一列是COF_NAME,其中包含type的值VARCHAR。第二列是PRICE,其中包含type的值REAL,依此类推。请注意,列类型是数据源中使用的数据类型,而不是Java编程语言中的类型。要获取或更新COF_NAME列中的值,请使用方法getString或updateString,驱动程序将VARCHAR像通常那样将其转换为类型。<metadata> <column-count>2</column-count> <column-definition> <column-index>1</column-index> <auto-increment>false</auto-increment> <case-sensitive>false</case-sensitive> <currency>false</currency> <nullable>0</nullable> <signed>false</signed> <searchable>true</searchable> <column-display-size> 32 </column-display-size> <column-label>COF_NAME</column-label> <column-name>COF_NAME</column-name> <schema-name></schema-name> <column-precision>32</column-precision> <column-scale>0</column-scale> <table-name>coffees</table-name> <catalog-name>testdb</catalog-name> <column-type>12</column-type> <column-type-name> VARCHAR </column-type-name> </column-definition> <column-definition> <column-index>2</column-index> <auto-increment>false</auto-increment> <case-sensitive>true</case-sensitive> <currency>false</currency> <nullable>0</nullable> <signed>true</signed> <searchable>true</searchable> <column-display-size> 12 </column-display-size> <column-label>PRICE</column-label> <column-name>PRICE</column-name> <schema-name></schema-name> <column-precision>10</column-precision> <column-scale>2</column-scale> <table-name>coffees</table-name> <catalog-name>testdb</catalog-name> <column-type>3</column-type> <column-type-name> DECIMAL </column-type-name> </column-definition> </metadata>
- Data
- 数据部分提供WebRowSet对象中每一行每一列d的值
<data> <currentRow> <columnValue>Colombian</columnValue> <columnValue>7.99</columnValue> </currentRow> <currentRow> <columnValue> Colombian_Decaf </columnValue> <columnValue>8.99</columnValue> </currentRow> <currentRow> <columnValue>Espresso</columnValue> <columnValue>9.99</columnValue> </currentRow> <currentRow> <columnValue>French_Roast</columnValue> <columnValue>8.99</columnValue> </currentRow> <currentRow> <columnValue>French_Roast_Decaf</columnValue> <columnValue>9.99</columnValue> </currentRow> </data>
- 数据部分提供WebRowSet对象中每一行每一列d的值
- 更改WebRowSet对象
- 更改方式与CachedRowSet对象,但是WebRowSet对象会跟踪更新、插入、删除,以便writeXml方法可以写入当前值和y原始值
- 插入行
xml文档中显示priceList.absolute(3); priceList.moveToInsertRow(); priceList.updateString(COF_NAME, "Kona"); priceList.updateFloat(PRICE, 8.99f); priceList.insertRow(); priceList.moveToCurrentRow();
<insertRow> <columnValue>Kona</columnValue> <columnValue>8.99</columnValue> </insertRow>
- 删除行
xml文档中priceList.absolute(3); priceList.deleteRow();
<deleteRow> <columnValue>浓咖啡</columnValue> <columnValue> 9.99 </columnValue> </deleteRow>
- 修改行
xml文档中priceList.first(); priceList.updateFloat(PRICE, 6.99);
<currentRow> <columnValue>Colombian</columnValue> <columnValue>7.99</columnValue> <updateRow>6.99</updateRow> </currentRow>
- xml在插入一删除一行、更新一行显示内容:
<data> <insertRow> <columnValue>Kona</columnValue> <columnValue>8.99</columnValue> </insertRow> <currentRow> <columnValue>Colombian</columnValue> <columnValue>7.99</columnValue> <updateRow>6.99</updateRow> </currentRow> <currentRow> <columnValue> Colombian_Decaf </columnValue> <columnValue>8.99</columnValue> </currentRow> <deleteRow> <columnValue>Espresso</columnValue> <columnValue>9.99</columnValue> </deleteRow> <currentRow> <columnValue>French_Roast</columnValue> <columnValue>8.99</columnValue> </currentRow> <currentRow> <columnValue> French_Roast_Decaf </columnValue> <columnValue>9.99</columnValue> </currentRow> </data>
高级数据类型
-
ANSI/ISO SQL标准的最新版本通常称为SQL:2003.该标准指定以下数据类型:
- SQL92内置类型,包括熟悉的SQL类类型如CHAR、FLOAT和DATE
- SQL99内置类型
- BOOLEAN:布尔值(true,false)
- BLOB:二进制大对象
- CLOB:字符大对象
- SQL2003新内置类型
- XML:xml对象
- 用户定义类型
- 结构化类型:用户定义类型,如
CREATE TYPE PLANE_POINT AS (X FLOAT, Y FLOAT) NOT FINAL
- DISTINCT类型:基于内置类型的用户定义类型;如:
CREATE TYPE MONEY AS NUMERIC(10,2) FINAL
- 结构化类型:用户定义类型,如
- 构造类型:基于给定基本类型的新类型
- REF(structured-type):持久的表示驻留在数据库中的结构化类型的实例的指针
- base-type ARRAY[n]:n个基本类型元素的数组
- 定位器:指向数据库服务器上数据的逻辑指针的实体。通常指太大而无法在客户端实现的数据,如图像和音频
- LOCATOR(structured-type):服务器中结构化实例的d定位器
- LOCATOR(array):服务器中数组的定位器
- LOCATOR(blob):服务器中二进制大对象的定位器
- LOCATOR(clob):服务器中字符大对象的定位器
- Datalink:用于管理数据源外部数据的类型
-
映射高级数据类型
- JDBC API为SQL:2003标准指定的高级数据类型提供默认映射
- 数据类型及yi映射接口类
- BLOB:Blob界面
- CLOB:Clob界面
- NCLOB:NClob界面
- ARRAY:Array界面
- XML:SQLXML界面
- 结构化类型:Struct接口
- REF(structured-type):Ref界面
- ROWID:RowId界面
- DISTINCT:基本类型映射到的类型
- DATALINK:java.net.URL对象
-
使用高级数据类型
高级数据类型 getDataType方法 setDataType方法 updateDataType方法 BLOB getBlob setBlob updataBlob CLOB getClob setClob NCLOB getNClob setNClob updateNClob ARRAY getArray setArray updateArray XML getSQLXML setSQLXML updateSQLXML Structured type getObject setObject updateObject REF(structured type) getRef setRef updateRef ROWID getRowId setRowId updateRowId DISTINCT getBigDecimal setBigDecimal updateBigDecimal DATALINK getURL setURL updateURL 如:检索SQL Array值
ResultSet rs = stmt.executeQuery( "SELECT SCORES FROM STUDENTS " + "WHERE ID = 002238"); rs.next(); Array scores = rs.getArray("SCORES");
向数据库插入值
Clob notes = rs.getClob("NOTES"); PreparedStatement pstmt = con.prepareStatement( "UPDATE MARKETS SET COMMENTS = ? " + "WHERE SALES < 1000000"); pstmt.setClob(1, notes); pstmt.executeUpdate();
大对象
Bolb、Clob以及NClob对象的一个重要特点就是可以操作它们,而不必把所有的数据从数据库服务器到客户端计算机
- 向数据库添加大对象类型对象
- 添加Clob SQL值
逐行读取文件public void addRowToCoffeeDescriptions( String coffeeName, String fileName) throws SQLException { PreparedStatement pstmt = null; try { //创建Clob对象 Clob myClob = this.con.createClob(); //将字符流写入java对象流 Writer clobWriter = myClob.setCharacterStream(1); //逐行读取指定的文件 String str = this.readFile(fileName, clobWriter); System.out.println("Wrote the following: " + clobWriter.toString()); if (this.settings.dbms.equals("mysql")) { System.out.println( "MySQL, setting String in Clob " + "object with setString method"); myClob.setString(1, str); } System.out.println("Length of Clob: " + myClob.length()); String sql = "INSERT INTO COFFEE_DESCRIPTIONS " + "VALUES(?,?)"; pstmt = this.con.prepareStatement(sql); pstmt.setString(1, coffeeName); pstmt.setClob(2, myClob); pstmt.executeUpdate(); } catch (SQLException sqlex) { JDBCTutorialUtilities.printSQLException(sqlex); } catch (Exception ex) { System.out.println("Unexpected exception: " + ex.toString()); } finally { if (pstmt != null)pstmt.close(); } }
创建PreparedStatement对象插入Clob java对象private String readFile(String fileName, Writer writerArg) throws FileNotFoundException, IOException { BufferedReader br = new BufferedReader(new FileReader(fileName)); String nextLine = ""; StringBuffer sb = new StringBuffer(); while ((nextLine = br.readLine()) != null) { System.out.println("Writing: " + nextLine); writerArg.write(nextLine); sb.append(nextLine); } // Convert the content into to a string String clobData = sb.toString(); // Return the data. return clobData; }
PreparedStatement pstmt = null; // ... String sql = "INSERT INTO COFFEE_DESCRIPTIONS VALUES(?,?)"; pstmt = this.con.prepareStatement(sql); pstmt.setString(1, coffeeName); pstmt.setClob(2, myClob); pstmt.executeUpdate();
- 添加Clob SQL值
- 查询CLOB值
- 从指定值的行中检索CLOB值
public String retrieveExcerpt(String coffeeName, int numChar) throws SQLException { String description = null; Clob myClob = null; PreparedStatement pstmt = null; try { String sql = "select COF_DESC " + "from COFFEE_DESCRIPTIONS " + "where COF_NAME = ?"; pstmt = this.con.prepareStatement(sql); pstmt.setString(1, coffeeName); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { // 从ResultSet对象中检索clob对象 myClob = rs.getClob(1); System.out.println("Length of retrieved Clob: " + myClob.length()); } //从Clob对象中检错出子字符串 description = myClob.getSubString(1, numChar); } catch (SQLException sqlex) { JDBCTutorialUtilities.printSQLException(sqlex); } catch (Exception ex) { System.out.println("Unexpected exception: " + ex.toString()); } finally { if (pstmt != null) pstmt.close(); } return description; }
- 从指定值的行中检索CLOB值
- 添加和j检索BLOB对象
- 与Clob对象类似,使用Blob.setBinaryStream方法检索OutputStream对象以写入Blob java对象
- 释放大对象持有的资源
- Blob,,Clob和NClobJava对象至少在创建它们的事务期间保持有效。在长时间运行的事务中,这可能导致应用程序资源不足。
- 调用free方法释放资源
Clob aClob = con.createClob(); int numWritten = aClob.setString(1, val); aClob.free();
SQLXML对象
Connection接口为使用createSQLXML方法创建SQLXML对象提供了支持,创建的对象不包含任何数据
- 创建SQLXML对象
Connection con = DriverManager.getConnection(url, props); SQLXML xmlVal = con.createSQLXML(); xmlVal.setString(val);
- 在ResultSet中检索SQLXML值
SQLXML xmlVar = rs.getSQLXML(1);
- 访问SQLXML数据
- getString、getBinaryStream、getCharacterStream和getSource方法访问q其内部的内容
SQLXML xmlVal= rs.getSQLXML(1); String val = xmlVal.getString();
- getBinaryStream或getCharacterStream方法可用于获得InputStream或Reader可以直接传递到XML解析器对象
SQLXML sqlxml = rs.getSQLXML(column); InputStream binaryStream = sqlxml.getBinaryStream(); DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document result = parser.parse(binaryStream);
- getSource返回一个source对象,用作XML解析器和XSLT转换器的输入
SQLXML xmlVal= rs.getSQLXML(1); SAXSource saxSource = sqlxml.getSource(SAXSource.class); XMLReader xmlReader = saxSource.getXMLReader(); xmlReader.setContentHandler(myHandler); xmlReader.parse(saxSource.getInputSource());
- getString、getBinaryStream、getCharacterStream和getSource方法访问q其内部的内容
- 储存SQLXML对象
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO bio " + "(xmlData, authId) VALUES (?, ?)"); pstmt.setSQLXML(1, authorData); pstmt.setInt(2, authorId);
- 初始化SQLXML对象
- SQLXML接口提供了setString、setBinaryStream、setCharacterStream或setResult方法用来初始化通过Connection.createSQLXML创建的SQLXML对象
- 使用setResult方法返回SQLXML对象
SQLXML sqlxml = con.createSQLXML(); SAXResult saxResult = sqlxml.setResult(SAXResult.class); ContentHandler contentHandler = saxResult.getXMLReader().getContentHandler(); contentHandler.startDocument(); // set the XML elements and // attributes into the result contentHandler.endDocument();
- 使用setCharacterStream方法获取Writer对象以初始化SQLXML
SQLXML sqlxml = con.createSQLXML(); Writer out= sqlxml.setCharacterStream(); BufferedReader in = new BufferedReader(new FileReader("xml/foo.xml")); String line = null; while((line = in.readLine() != null) { out.write(line); }
- 释放SQLXML资源
- SQLXML对象在创建它们的事务期间保持有效。在长时间运行的事务中,这可能导致应用程序资源不足。
- 调用free方法释放资源
SQLXML xmlVar = con.createSQLXML(); xmlVar.setString(val); xmlVar.free();
- 样例代码
- 在MySqlzzh中使用XML数据
- MySql不支持XML数据类型,将XML数据储存在LONGTEXT Type列中
create table RSS_FEEDS (RSS_NAME varchar(32) NOT NULL, RSS_FEED_XML longtext NOT NULL, PRIMARY KEY (RSS_NAME));
- 将数据转换为Document类型对象
Node titleElement = (Node)xPath.evaluate("/rss/channel/title[1]", doc, XPathConstants.NODE);
- 创建Doeument对象,j将XML内存存储在document对象中
// For databases that support the SQLXML // data type, this creates a // SQLXML object from // org.w3c.dom.Document. System.out.println("Adding XML file " + fileName); String insertRowQuery = "insert into RSS_FEEDS " + "(RSS_NAME, RSS_FEED_XML) values " + "(?, ?)"; insertRow = con.prepareStatement(insertRowQuery); insertRow.setString(1, titleString); System.out.println("Creating SQLXML object with MySQL"); rssData = con.createSQLXML(); System.out.println("Creating DOMResult object"); DOMResult dom = (DOMResult)rssData.setResult(DOMResult.class); dom.setNode(doc); insertRow.setSQLXML(2, rssData); System.out.println("Running executeUpdate()"); insertRow.executeUpdate();
- MySql不支持XML数据类型,将XML数据储存在LONGTEXT Type列中
- 在Java DB中使用XML数据
- 创建表
create table RSS_FEEDS (RSS_NAME varchar(32) NOT NULL, RSS_FEED_XML xml NOT NULL, PRIMARY KEY (RSS_NAME));
- Java DB支持XMLsshu数据类型,但不支持SQLXML数据类型,必须将rre任何XML数据转换为z字符格式,然后使用JavaDB操作符XMLPARSE将其转换为XML数据类型
String insertRowQuery = "insert into RSS_FEEDS " + "(RSS_NAME, RSS_FEED_XML) values " + "(?, xmlparse(document cast " + "(? as clob) preserve whitespace))";
- 检索时必须将XML内容z作为字符串检索
String query = "select RSS_NAME, " + "xmlserialize " + "(RSS_FEED_XML as clob) " + "from RSS_FEEDS";
- 创建表
- 在MySqlzzh中使用XML数据
Array对象
MySql和JavaDB当前不支持SQL Array数据类型
- 创建Array对象
- 使用createArrayOf创建Array对象
create table REGIONS (REGION_NAME varchar(32) NOT NULL, ZIPS varchar32 ARRAY[10] NOT NULL, PRIMARY KEY (REGION_NAME)); insert into REGIONS values( 'Northwest', '{"93101", "97201", "99210"}'); insert into REGIONS values( 'Southwest', '{"94105", "90049", "92027"}'); Connection con = DriverManager.getConnection(url, props); String [] northEastRegion = { "10022", "02110", "07399" }; Array aArray = con.createArrayOf("VARCHAR", northEastRegionnewYork);
- 使用createArrayOf创建Array对象
- 检索和访问ResultSet中的数组值
ResultSet rs = stmt.executeQuery( "SELECT region_name, zips FROM REGIONS"); while (rs.next()) { //返回列值作为Array对象 Array z = rs.getArray("ZIPS"); //将结果转换为String对象数组 String[] zips = (String[])z.getArray(); for (int i = 0; i < zips.length; i++) { if (!ZipCode.isValid(zips[i])) { // ... // Code to display warning } } }
- 存储和更新Array对象
- 使用PreparedStatement.setArray方法和setObject方法将Array值当作参数传给PreparedStatement对象
PreparedStatement pstmt = con.prepareStatement( "insert into REGIONS (region_name, zips) " + "VALUES (?, ?)"); pstmt.setString(1, "NorthEast"); pstmt.setArray(2, northEastRegion); pstmt.executeUpdate();
- 使用PreparedStatement.updateArray和updateObject方法更新列
- 使用PreparedStatement.setArray方法和setObject方法将Array值当作参数传给PreparedStatement对象
- 释放阵列资源
- 使用feee方法释放资源
Array aArray = con.createArrayOf("VARCHAR", northEastRegionnewYork); // ... aArray.free();
- 使用feee方法释放资源
DISTINCT数据类型
MySql和JavaDB当前不支持SQL DISTINCT数据类型
- 作为一种基于现有内置类型之一的用户定义类型,它没有接口作为Java编程语言中的映射。相反,DISTINCT数据类型的标准映射是其基础SQL数据类型映射到的Java类型。
- 定义新的DISTINCT数据类型
CREATE TYPE STATE AS CHAR(2);
- 使用替代语法创建DISTINCT数据类型
CREATE DISTINCT TYPE STATE AS CHAR(2);
- 检索
String state = rs.getString(4);
- setString储存值,updateString修改值
结构化类型
MySql和JavaDB当前不支持用户自定义类型
- 结构化类型概述
- j结构化类型和DISTINCTl类型是用户ke可以在SQL中定义的两种数据类型。通常被称为UDT(用户自定义类型),可以使用SQL CREATE TYPE语句创建
- 创建新的结构化数据类型
CREATE TYPE ADDRESS ( NUM INTEGER, STREET VARCHAR(40), CITY VARCHAR(40), STATE CHAR(2), ZIP CHAR(5) );
- 将定义发送到数据库
String createAddress = "CREATE TYPE ADDRESS " + "(NUM INTEGER, STREET VARCHAR(40), " + "CITY VARCHAR(40), STATE CHAR(2), ZIP CHAR(5))"; Statement stmt = con.createStatement(); stmt.executeUpdate(createAddress);
- 在结构化类型中使用DISTINCT类型
- 例如手机号为数字组成,可以将这种类型的数据作为只有一个属性的结构化类型
对于某些驱动程序,用以下定义CREATE TYPE PHONE_NO AS CHAR(10);
CREATE DISTINCT TYPE PHONE_NO AS CHAR(10);
- DISTINCT类型始终基于另一个数据类型且该类型必须是预定义的类型,DISTINCT不能基于用户自定义的类型
- 检索DISRINCT数据类型的值
String phoneNumber = rs.getString(4);
- 设置输入参数,参数类型与数据库定义有关
pstmt.setString(1, phoneNumber);
- 发送到数据库
stmt.executeUpdate( "CREATE TYPE PHONE_NO AS CHAR(10)");
- 将列类型作为结构化类型中属性的数据类型
CREATE TYPE MANAGER ( MGR_ID INTEGER, LAST_NAME VARCHAR(40), FIRST_NAME VARCHAR(40), PHONE PHONE_NO );
- 发送到数据库
String createManager = "CREATE TYPE MANAGER " + "(MGR_ID INTEGER, LAST_NAME " + "VARCHAR(40), " + "FIRST_NAME VARCHAR(40), " + "PHONE PHONE_NO)"; stmt.executeUpdate(createManager);
- 例如手机号为数字组成,可以将这种类型的数据作为只有一个属性的结构化类型
- 结构化类型引用
- 创建表
CREATE TABLE MANAGERS OF MANAGER (OID REF(MANAGER) VALUES ARE SYSTEM GENERATED);
- 插入数据
INSERT INTO MANAGERS ( MGR_ID, LAST_NAME, FIRST_NAME, PHONE) VALUES ( 000001, 'MONTOYA', 'ALFREDO', '8317225600' ); INSERT INTO MANAGERS ( MGR_ID, LAST_NAME, FIRST_NAME, PHONE) VALUES ( 000002, 'HASKINS', 'MARGARET', '4084355600' ); INSERT INTO MANAGERS ( MGR_ID, LAST_NAME, FIRST_NAME, PHONE) VALUES ( 000003, 'CHEN', 'HELEN', '4153785600' );
- 访问数据
String selectMgr = "SELECT OID FROM MANAGERS " + "WHERE MGR_ID = 000001"; ResultSet rs = stmt.executeQuery(selectMgr); rs.next(); //Ref对象标识指向结构化类型的逻辑指针 Ref manager = rs.getRef("OID");
- 创建表
- 创建SQL REF对象
package com.oracle.tutorial.jdbc; import java.sql.*; public class CreateRef { public static void main(String args[]) { JDBCTutorialUtilities myJDBCTutorialUtilities; Connection myConnection = null; if (args[0] == null) { System.err.println("Properties file not specified " + "at command line"); return; } else { try { myJDBCTutorialUtilities = new JDBCTutorialUtilities(args[0]); } catch (Exception e) { System.err.println("Problem reading properties " + "file " + args[0]); e.printStackTrace(); return; } } Connection con = null; Statement stmt = null; try { String createManagers = "CREATE TABLE " + "MANAGERS OF MANAGER " + "(OID REF(MANAGER) " + "VALUES ARE SYSTEM " + "GENERATED)"; String insertManager1 = "INSERT INTO MANAGERS " + "(MGR_ID, LAST_NAME, " + "FIRST_NAME, PHONE) " + "VALUES " + "(000001, 'MONTOYA', " + "'ALFREDO', " + "'8317225600')"; String insertManager2 = "INSERT INTO MANAGERS " + "(MGR_ID, LAST_NAME, " + "FIRST_NAME, PHONE) " + "VALUES " + "(000002, 'HASKINS', " + "'MARGARET', " + "'4084355600')"; String insertManager3 = "INSERT INTO MANAGERS " + "(MGR_ID, LAST_NAME, " + "FIRST_NAME, PHONE) " + "VALUES " + "(000003, 'CHEN', 'HELEN', " + "'4153785600')"; con = myJDBCTutorialUtilities.getConnection(); con.setAutoCommit(false); stmt = con.createStatement(); stmt.executeUpdate(createManagers); stmt.addBatch(insertManager1); stmt.addBatch(insertManager2); stmt.addBatch(insertManager3); int [] updateCounts = stmt.executeBatch(); con.commit(); System.out.println("Update count for: "); for (int i = 0; i < updateCounts.length; i++) { System.out.print(" command " + (i + 1) + " = "); System.out.println(updateCounts[i]); } } catch(BatchUpdateException b) { System.err.println("-----BatchUpdateException-----"); System.err.println("Message: " + b.getMessage()); System.err.println("SQLState: " + b.getSQLState()); System.err.println("Vendor: " + b.getErrorCode()); System.err.print("Update counts for " + "successful commands: "); int [] rowsUpdated = b.getUpdateCounts(); for (int i = 0; i < rowsUpdated.length; i++) { System.err.print(rowsUpdated[i] + " "); } System.err.println(""); } catch(SQLException ex) { System.err.println("------SQLException------"); System.err.println("Error message: " + ex.getMessage()); System.err.println("SQLState: " + ex.getSQLState()); System.err.println("Vendor: " + ex.getErrorCode()); } finally { if (stmt != null) { stmt.close(); } JDBCTutorialUtilities.closeConnection(con); } } }
- 使用用户自定义类型作为列值
- 创建类型
CREATE TYPE COF_ARRAY AS ARRAY(10) OF VARCHAR(40);
- 使用自定义类型创建表
CREATE TABLE STORES ( STORE_NO INTEGER, LOCATION ADDRESS, COF_TYPES COF_ARRAY, MGR REF(MANAGER) );
- 创建类型
- 将自定义类型插入表中
INSERT INTO STORES VALUES ( 100001, ADDRESS(888, 'Main_Street', 'Rancho_Alegre', 'CA', '94049'), COF_ARRAY('Colombian', 'French_Roast', 'Espresso', 'Colombian_Decaf', 'French_Roast_Decaf'), SELECT OID FROM MANAGERS WHERE MGR_ID = 000001 );
- 发送到数据库
发送多个INSET INTO语句,使用批处理更新String insertMgr = "INSERT INTO STORES VALUES " + "(100001, " + "ADDRESS(888, 'Main_Street', " + "'Rancho_Alegre', 'CA', " + "'94049'), " + "COF_ARRAY('Colombian', " + "'French_Roast', 'Espresso', " + "'Colombian_Decaf', " + "'French_Roast_Decaf'}, " + "SELECT OID FROM MANAGERS " + "WHERE MGR_ID = 000001)"; stmt.executeUpdate(insertMgr);
package com.oracle.tutorial.jdbc; import java.sql.*; public class InsertStores { public static void main(String args[]) { JDBCTutorialUtilities myJDBCTutorialUtilities; Connection myConnection = null; if (args[0] == null) { System.err.println( "Properties file " + "not specified " + "at command line"); return; } else { try { myJDBCTutorialUtilities = new JDBCTutorialUtilities(args[0]); } catch (Exception e) { System.err.println( "Problem reading " + "properties file " + args[0]); e.printStackTrace(); return; } } Connection con = null; Statement stmt = null; try { con = myJDBCTutorialUtilities.getConnection(); con.setAutoCommit(false); stmt = con.createStatement(); String insertStore1 = "INSERT INTO STORES VALUES (" + "100001, " + "ADDRESS(888, 'Main_Street', " + "'Rancho_Alegre', 'CA', " + "'94049'), " + "COF_ARRAY('Colombian', " + "'French_Roast', " + "'Espresso', " + "'Colombian_Decaf', " + "'French_Roast_Decaf'), " + "(SELECT OID FROM MANAGERS " + "WHERE MGR_ID = 000001))"; stmt.addBatch(insertStore1); String insertStore2 = "INSERT INTO STORES VALUES (" + "100002, " + "ADDRESS(1560, 'Alder', " + "'Ochos_Pinos', " + "'CA', '94049'), " + "COF_ARRAY('Colombian', " + "'French_Roast', " + "'Espresso', " + "'Colombian_Decaf', " + "'French_Roast_Decaf', " + "'Kona', 'Kona_Decaf'), " + "(SELECT OID FROM MANAGERS " + "WHERE MGR_ID = 000001))"; stmt.addBatch(insertStore2); String insertStore3 = "INSERT INTO STORES VALUES (" + "100003, " + "ADDRESS(4344, " + "'First_Street', " + "'Verona', " + "'CA', '94545'), " + "COF_ARRAY('Colombian', " + "'French_Roast', " + "'Espresso', " + "'Colombian_Decaf', " + "'French_Roast_Decaf', " + "'Kona', 'Kona_Decaf'), " + "(SELECT OID FROM MANAGERS " + "WHERE MGR_ID = 000002))"; stmt.addBatch(insertStore3); String insertStore4 = "INSERT INTO STORES VALUES (" + "100004, " + "ADDRESS(321, 'Sandy_Way', " + "'La_Playa', " + "'CA', '94544'), " + "COF_ARRAY('Colombian', " + "'French_Roast', " + "'Espresso', " + "'Colombian_Decaf', " + "'French_Roast_Decaf', " + "'Kona', 'Kona_Decaf'), " + "(SELECT OID FROM MANAGERS " + "WHERE MGR_ID = 000002))"; stmt.addBatch(insertStore4); String insertStore5 = "INSERT INTO STORES VALUES (" + "100005, " + "ADDRESS(1000, 'Clover_Road', " + "'Happyville', " + "'CA', '90566'), " + "COF_ARRAY('Colombian', " + "'French_Roast', " + "'Espresso', " + "'Colombian_Decaf', " + "'French_Roast_Decaf'), " + "(SELECT OID FROM MANAGERS " + "WHERE MGR_ID = 000003))"; stmt.addBatch(insertStore5); int [] updateCounts = stmt.executeBatch(); ResultSet rs = stmt.executeQuery( "SELECT * FROM STORES"); System.out.println("Table STORES after insertion:"); System.out.println("STORE_NO " + "LOCATION " + "COF_TYPE " + "MGR"); while (rs.next()) { int storeNo = rs.getInt("STORE_NO"); Struct location = (Struct)rs.getObject("LOCATION"); Object[] locAttrs = location.getAttributes(); Array coffeeTypes = rs.getArray("COF_TYPE"); String[] cofTypes = (String[])coffeeTypes.getArray(); Ref managerRef = rs.getRef("MGR"); PreparedStatement pstmt = con.prepareStatement( "SELECT MANAGER " + "FROM MANAGERS " + "WHERE OID = ?"); pstmt.setRef(1, managerRef); ResultSet rs2 = pstmt.executeQuery(); rs2.next(); Struct manager = (Struct)rs2.getObject("MANAGER"); Object[] manAttrs = manager.getAttributes(); System.out.print(storeNo + " "); System.out.print( locAttrs[0] + " " + locAttrs[1] + " " + locAttrs[2] + ", " + locAttrs[3] + " " + locAttrs[4] + " "); for (int i = 0; i < cofTypes.length; i++) System.out.print( cofTypes[i] + " "); System.out.println( manAttrs[1] + ", " + manAttrs[2]); rs2.close(); pstmt.close(); } rs.close(); } catch(BatchUpdateException b) { System.err.println("-----BatchUpdateException-----"); System.err.println("SQLState: " + b.getSQLState()); System.err.println("Message: " + b.getMessage()); System.err.println("Vendor: " + b.getErrorCode()); System.err.print("Update counts: "); int [] updateCounts = b.getUpdateCounts(); for (int i = 0; i < updateCounts.length; i++) { System.err.print(updateCounts[i] + " "); } System.err.println(""); } catch(SQLException ex) { System.err.println("SQLException: " + ex.getMessage()); System.err.println("SQLState: " + ex.getSQLState()); System.err.println("Message: " + ex.getMessage()); System.err.println("Vendor: " + ex.getErrorCode()); } finally { if (stmt != null) { stmt.close(); } JDBCTutorialUtilities.closeConnection(con); } } } }
自定义类型映射
MySql不支持自定义类型。MySql和JavaDB不支持结构化类型和DISTINCT类型
- 实现SQL Data
- 自定义映射的第一件事是创建一个实现SqlData接口的类
- 定义结构化类型
CREATE TYPE ADDRESS ( NUM INTEGER, STREET VARCHAR(40), CITY VARCHAR(40), STATE CHAR(2), ZIP CHAR(5) );
- 定义结构化类型映射类
public class Address implements SQLData { public int num; public String street; public String city; public String state; public String zip; private String sql_type; public String getSQLTypeName() { return sql_type; } public void readSQL(SQLInput stream, String type) throws SQLException { sql_type = type; num = stream.readInt(); street = stream.readString(); city = stream.readString(); state = stream.readString(); zip = stream.readString(); } public void writeSQL(SQLOutput stream) throws SQLException { stream.writeInt(num); stream.writeString(street); stream.writeString(city); stream.writeString(state); stream.writeString(zip); } }
- 使用Connection的Type Map
- 添加自定义映射
java.util.Map map = con.getTypeMap(); map.put("SchemaName.ADDRESS", Class.forName("Address")); con.setTypeMap(map);
- Java编程语言Struct对象的标准映射
ResultSet rs = stmt.executeQuery( "SELECT LOCATION " + "WHERE STORE_NO = 100003"); rs.next(); Struct address = (Struct)rs.getObject("LOCATION");
- 自定义映射
ResultSet rs = stmt.executeQuery( "SELECT LOCATION " + "WHERE STORE_NO = 100003"); rs.next(); Address store_3 = (Address)rs.getObject("LOCATION");
- 使用自定义映射更新数据
ResultSet rs = stmt.executeQuery( "SELECT LOCATION " + "WHERE STORE_NO = 100003"); rs.next(); Address store_3 = (Address)rs.getObject("LOCATION"); store_3.num = 1800; store_3.street = "Artsy_Alley"; store_3.city = "Arden"; store_3.state = "CA"; store_3.zip = "94546"; PreparedStatement pstmt = con.prepareStatement( "UPDATE STORES " + "SET LOCATION = ? " + "WHERE STORE_NO = 100003"); pstmt.setObject(1, store_3); pstmt.executeUpdate();
- 不使用自定义映射 更新
PreparedStatement pstmt = con.prepareStatement( "UPDATE STORES " + "SET LOCATION.NUM = 1800, " + "LOCATION.STREET = 'Artsy_Alley', " + "LOCATION.CITY = 'Arden', " + "LOCATION.STATE = 'CA', " + "LOCATION.ZIP = '94546' " + "WHERE STORE_NO = 100003"); pstmt.executeUpdate;
- 添加自定义映射
- 使用自己的Type Map
- 对于同一个UDF,可能有多个自定义映射,只要每个映射ddo都设置有实现SqlData接口的类和类型y映射中的条目即可
- 如果没有将类型映射传递给可以接受的方法,驱动程序j将默认使用与连接关联的类型映射
DataLink对象
DataLink值通过URL引用基础数据源之外的z资源。URL(统一资源定位符)是指向万维网资源的指针。资源可以是文件或目录,也可以是更复杂对象的引用
- 储存对外部资源的引用
- 使用PreparedStatement.setURL方法为对象指定URL
public void addURLRow(String description, String url) throws SQLException { PreparedStatement pstmt = null; try { pstmt = this.con.prepareStatement( "INSERT INTO data_repository" + "(document_name,url) VALUES (?,?)"); pstmt.setString(1, description); pstmt.setURL(2,new URL(url)); pstmt.execute(); } catch (SQLException sqlex) { JDBCTutorialUtilities.printSQLException(sqlex); } catch (Exception ex) { System.out.println("Unexpected exception"); ex.printStackTrace(); } finally { if (pstmt != null) { pstmt.close(); } } }
- 使用PreparedStatement.setURL方法为对象指定URL
- 检索对外部数据的引用
- 使用ResultSet.getURL检索对作为URL对象的外部数据的引用
public static void viewTable(Connection con, Proxy proxy) throws SQLException, IOException { Statement stmt = null; String query = "SELECT document_name, url " + "FROM data_repository"; try { stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(query); if ( rs.next() ) { String documentName = null; java.net.URL url = null; documentName = rs.getString(1); // Retrieve the value as a URL object. // 从结果集中检索URL作为对象 url = rs.getURL(2); if (url != null) { // Retrieve the contents // from the URL //访问URL对象引用的资源 URLConnection myURLConnection = url.openConnection(proxy); BufferedReader bReader = new BufferedReader( new InputStreamReader( myURLConnection. getInputStream())); System.out.println("Document name: " + documentName); String pageContent = null; while ((pageContent = bReader.readLine()) != null ) { // Print the URL contents System.out.println(pageContent); } } else { System.out.println("URL is null"); } } } catch (SQLException e) { JDBCTutorialUtilities.printSQLException(e); } catch(IOException ioEx) { System.out.println("IOException caught: " + ioEx.toString()); } catch (Exception ex) { System.out.println("Unexpected exception"); ex.printStackTrace(); } finally { if (stmt != null) { stmt.close(); } } }
- 使用服务器名称和端口号床在HTTP代理
Proxy myProxy; InetSocketAddress myProxyServer; myProxyServer = new InetSocketAddress("www-proxy.example.com", 80); myProxy = new Proxy(Proxy.Type.HTTP, myProxyServer);
- 使用ResultSet.getURL检索对作为URL对象的外部数据的引用
RowId对象
MySQL和Java DB当前不支持JDBC RowId接口
RowId对象表示在数据库中的表中的行的地址。但DowId不是标准的SQL类型。访问单行的最快方法,并且是表中行的w唯一标识。不能作为主键
- 检索RowId对象
- 返回对象为不变对象,可以作为唯一标识
java.sql.RowId rowId_1 = rs.getRowId(1);
- 返回对象为不变对象,可以作为唯一标识
- 使用RowId对象
- 将RowId对象设置为PreparedStatement对象的参数
Connection conn = ds.getConnection(username, password); PreparedStatement ps = conn.prepareStatement( "INSERT INTO BOOKLIST" + "(ID, AUTHOR, TITLE, ISBN) " + "VALUES (?, ?, ?, ?)"); ps.setRowId(1, rowId_1);
- 使用可更新RowSet对象的特定RowId对象更新列
ResultSet rs = ... rs.next(); rs.updateRowId(1, rowId_1);
- 将RowId对象设置为PreparedStatement对象的参数
- RowId有效期
- 只要被识别的行没有被删除和RowId目标在由该数据指定的寿命范围内
- 使用DataBaseMetaData.getRowIdLifeTime方法获取RowId有效期
public static void rowIdLifetime(Connection conn) throws SQLException { DatabaseMetaData dbMetaData = conn.getMetaData(); RowIdLifetime lifetime = dbMetaData.getRowIdLifetime(); switch (lifetime) { case ROWID_UNSUPPORTED: System.out.println("ROWID type not supported"); break; case ROWID_VALID_FOREVER: System.out.println("ROWID has unlimited lifetime"); break; case ROWID_VALID_OTHER: System.out.println("ROWID has indeterminate lifetime"); break; case ROWID_VALID_SESSION: System.out.println( "ROWID type has lifetime that " + "is valid for at least the " + "containing session"); break; case ROWID_VALID_TRANSACTION: System.out.println( "ROWID type has lifetime that " + "is valid for at least the " + "containing transaction"); break; } }