26、可滚动结果集与分页技术
static void scroll() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//在创建一个Statement的时候指定可滚动的结果集的类型
st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
//在mysql中通过limit关键字实现分页,每种数据库产品的关键字不同例如:Oracle使用rownum,sqlServer用top
//现在有几十中关系型数据库如果数据库不支持这种关键字进行分页的时候可以用滚动的结果集来实现分页,但是
//性能比较低
rs = st.executeQuery("select id, name, money, birthday from user limit 150, 10");
while (rs.next()) {
System.out.println(rs.getObject("id") + "\t"
+ rs.getObject("name") + "\t"
+ rs.getObject("birthday") + "\t"
+ rs.getObject("money"));
}
//绝对定位,可以直接定位到rs所有返回结果中指定的一条记录上
rs.absolute(150);
int i = 0;
//可以通过i来控制循环次数,实现分页效果但是要数据库产品或者驱动支持此功能!
while (rs.next() && i < 10) {
i++;
System.out.println(rs.getObject("id") + "\t"
+ rs.getObject("name") + "\t"
+ rs.getObject("birthday") + "\t"
+ rs.getObject("money"));
}
//如果上面设定的结果集是可以滚动的,那么你还可以用里面的很多的方法,在此不列举了
} finally {
JdbcUtils.free(rs, st, conn);
}
}
27、可更新和对更新敏感的结果集
static void read() throws SQLException, InterruptedException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
//设置滚动结果集的类型为:ResultSet.TYPE_SCROLL_SENSITIVE,就是能感知到数据库的变化
st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
// 4.执行语句
rs = st
.executeQuery("select id, name, money, birthday from user where id < 5");
// 5.处理结果
//下面让rs每循环一次rs睡眠10秒钟,然后再这个过程中我们用mysql客户端修改数据库中的数据
//我们看看他读出来的是修改前的数据,还是修改后的。我们在上面设置的可滚动的结果集的类型
//是ResultSet.TYPE_SCROLL_SENSITIVE,也就是能感知数据库的变化,那如果在rs没有读出数据库里的
//那条数据之前我们在mysql的客户端将原先的数据修改掉,这里读出来的数据应该是修改后的数据,但是在
//测试的时候读出的数据却依然是修改之前的,这应该和数据库的驱动有关系
//但是如果是能感知数据库的变化,那么数据库的性能也是降低了,你执行executeQuery()方法后,他已经将数据查询完成
//打包后给你发送过来了,如果察觉到数据库的变化那么他要在输出之前在查询一遍数据库,这种需求用的比较少,作为
//了解即可
while (rs.next()) {
int id = rs.getInt("id");
System.out.println("show " + id + "...");
Thread.sleep(10000);
System.out.println(id + "\t" + rs.getObject("name") + "\t"
+ rs.getObject("birthday") + "\t"
+ rs.getObject("money"));
String name = rs.getString("name");
//可更新的结果集,我们并不建议这样做因为上面的sql语句是查询操作
//但是下面还隐藏着更新操作,对于程序的可读性不好,这种需求也比较少
//做了解即可
if("lisi".equals(name)) {
rs.updateFloat("money",300f);
//修改完成后要修改一行
rs.updateRow();
}
}
} finally {
JdbcUtils.free(rs, st, conn);
}
}
28、数据库的元数据信息:
DatabaseMetaData对象中包含了当前数据库产品的很多的信息,他有很多返回值类型为boolean的方法,来判断
当前的数据库是否支持某些功能,例如事务的支持,隔离级别 版本号等等,对于我们编写程序来说不常用,但是
在框架的编写中经常会用到,例如hibernate,他要屏蔽不同数据库之间的区别,那么他就要知道当前是什么数据库
然后做出相应的判断处理:在使用hibernate的时候有一项是配置数据库的方言,其实就是指定你使用的是什么数据库产品
如果你不进行指定,hibernate会自动的尝试着去检测当前数据库产品的类型,其实就是根据DatabaseMetaData来检测的
public static void main(String[] args) throws SQLException {
java.sql.Connection conn = JdbcUtils.getConnection();
//得到数据库的元信息
DatabaseMetaData dbmd = conn.getMetaData();
//取出当前使用数据库的名称
System.out.println("db name: " + dbmd.getDatabaseProductName());
//看看当前数据库支不支持事务
System.out.println("tx: " + dbmd.supportsTransactions());
conn.close();
}
29、参数的元数据信息
/**链接数据库的url为:url = "jdbc:mysql://localhost:3306/jdbc?generateSimpleParameterMetadata=true
* 要加入 generateSimpleParameterMetadata=true时才行,否则会抛
* “java.sql.SQLException: Parameter metadata not available for the given statement”,
* 因为mysql驱动默认generateSimpleParameterMetadata=false只有设置为true metadata类型会
* 将每一个参数反射为Varchar类型
* @author guohailong
*
*/
public static void main(String[] args) throws SQLException {
String sql = "select * from user where name = ? and sex = ?";
Object[] params = {"zhangsan", "男"};
query(sql, params);
}
public static void query(String sql, Object[] param) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
pstmt = conn.prepareStatement(sql);
ParameterMetaData pmd = pstmt.getParameterMetaData();
int paramsCount = pmd.getParameterCount();
//得到参数信息的元数据
for(int i=1; i<=paramsCount; i++) {
System.out.print(pmd.getParameterClassName(i) + "\t");
System.out.print(pmd.getParameterType(i) + "\t");
System.out.print(pmd.getParameterTypeName(i) + "\t");
System.out.println();
//用for循环的方法给sql语句中的占位符赋值,但是要约定:sql语句中占位符的所表示的类型
//和个数和参数数组中是一致的
pstmt.setObject(i, param[i -1]);
}
rs = pstmt.executeQuery();
while(rs.next()) {
System.out.println(rs.getString(2));
}
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
30、将结果集元数据封装为Map
现在我们有一种需求将ResultSet结果集中的数据封装成Map map的key是数据库中字段的值value就是在字段中的值
public static void main(String[] args) {
Map<String, Object> datas = read("select id, name from user");
}
private static Map<String, Object> read(String sql) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
//得到ResultSet的元数据
ResultSetMetaData rsmd = pstmt.getMetaData();
//得到一条ResultSet数据的列数
int colCount = rsmd.getColumnCount();
String[] colName = new String[colCount];
for(int i=1; i<=colCount; i++) {
//得到参数的类名,java.lang.String
/*System.out.print(rsmd.getColumnClassName(i) + "\t");
//得到列名
System.out.print(rsmd.getColumnName(i) + "\t");
//得到别名:select name as n from user -->得到的是n
System.out.println(rsmd.getColumnLabel(i) + "\t");*/
colName[i-1] = rsmd.getColumnLabel(i);
}
//新建一个Map对象
Map<String, Object> data = new HashMap<String, Object>();
while(rs.next()) {
for(int i=1; i<=colName.length; i++) {
data.put(colName[i-1], rs.getObject(i));
System.out.println(colName[i-1] + "======" +rs.getObject(i) );
}
}
//返回Map对象
return data;
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}finally {
JdbcUtils.free(rs, pstmt, conn);
}
}
31、Java反射技术入门:
传递给你一个Class的对象,用它来构造一对象如果这个对象有无参的构造方法那么
clazz.newInstance(),直接newInstance就可了,但是如果没有无参的构造方法,就要首先根据参数类型
得到构造方法,然后再去构造对象,在张孝祥Java高级笔记中,已经详细的记录了这个问题在这里就不在重复了
32、Java反射的更多的细节
static void invoke1(Object obj, String methodName)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, Exception, NoSuchMethodException {
//得到类中所有声明的方法,包括私有方法但不能得到从父类继承来的任何方法
Method[] ms = obj.getClass().getDeclaredMethods();
//得到所有的方法包括从父类继承来的,但得不到私有方法
//下面得到属性和得到注解都一样,主要理解两个方法的不同
ms = obj.getClass().getMethods();
for (Method m : ms) {
// System.out.println(m.getName());
if (methodName.equals(m.getName()))
m.invoke(obj, null);
}
Method m = obj.getClass().getMethod(methodName, null);
m.invoke(obj, null);
}
static void field(Class clazz) throws Exception {
Field[] fs = clazz.getDeclaredFields();
//fs = clazz.getFields();
for (Field f : fs)
System.out.println(f.getName());
}
static void annon(Class clazz) throws Exception {
Annotation[] as = clazz.getAnnotations();
}
33、利用Java反射技术将查询结果封装为对象
在这个示例中,约定数据库的字段名要和属性的字段名一致, String methodName = "set" + 数据库的字段名。用这样的方法来构成
Javabean中属性的set方法来实现赋值操作,那么在传递sql语句的时候就有一定的局限性了,例如:你不能写 select id , name from user
因为这样得到的set方法setid, setname这样就没法完成赋值操作,要这样写:select id as Id, name as Name fromt user,然后用ResultSetMetadata
getColumnLabel()得到他的别名,然后遍历Javabean中所有的方法找到和我们这个名字一样的,然后执行就可以了,但是通过sql语句来操纵属性
名称然后构成方法名,这样的方式不大好。