为什么使用PreparedStatement
- 最重要的是避免Statement的sql注入问题
- 其次解决了拼串的繁琐,
- 还有很重要的一点因为PreparedStatement实现了预编译操做,在批量操做时,其效率原高于Statement.
- 并且可以操做Blob数据
通用的增删改操做
@Test
public void testCommonUpdate() {
// String sql = "delete from customers where id = ?";
// updataTest(sql,19);
String sql = "update `order` set order_name = ? where order_id = ?";
updataTest(sql,"Anna",4);
}
//通用的增删改操做
public void updataTest(String sql,Object ...args){//sql语句中占位符个数与可变形参个数必须相同
Connection conn = null;
PreparedStatement ps = null;
try {
//1.加载并注册驱动获取数据库的连接
conn = JdbcUtils.getConnection();
//2.预编译SQL语句返回PrepareStatement的实例
ps = conn.prepareStatement(sql);
//3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
//4.执行
ps.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//5.关闭资源
JdbcUtils.closeResource(conn, ps);
}
}
通用的返回一条记录
@Test
public void testGetInstance() {
String sql = "SELECT `order_id` orderId,`order_name` orderName,`order_date` orderDate FROM `order` WHERE order_id = ?";
Order instance = getInstance(Order.class, sql, 1);
System.out.println(instance);
sql = "select id,name,email,birth from customers where id = ?";
Customer instance2 = getInstance(Customer.class, sql,18 );
System.out.println(instance2);
}
/**
* 针对于不同表的通用的查询操做,返回表中的一条记录
* @param clazz
* @param sql
* @param args
* @return
*/
public <T> T getInstance(Class<T> clazz,String sql,Object ...args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//获取连接
conn = JdbcUtils.getConnection();
//获取PreparedStatement
ps = conn.prepareStatement(sql);
//填充占位符
for(int i = 0;i < args.length;i++) {//填充占位符从1开始
ps.setObject(i+1, args[i]);
}
//执行SQL语句
rs = ps.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
//类似于迭代器指针
if(rs.next()) {
// Order order = new Order();
T t = clazz.newInstance();
//遍历一条记录里的各个字段
for(int i = 0;i < columnCount;i++) {
//遍历每一个字段的名字为反射提供属性名和
// String columnName = metaData.getColumnName(i+1);
String columnLabel = metaData.getColumnLabel(i + 1);
Object columnValue = rs.getObject(i+1);
//为order指定的columnName赋值columnValue,通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columnValue);
}
return t;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭资源
JdbcUtils.closeResource(conn, ps, rs);
}
return null;
}
通用的返回多条记录
@Test
public void testGetListInstance() {
String sql = "SELECT `order_id` orderId,`order_name` orderName,`order_date` orderDate FROM `order` ";
List<Order> listInstance = getListInstance(Order.class, sql);
Iterator<Order> iterator = listInstance.iterator();
while(iterator.hasNext()) {
Order next = iterator.next();
System.out.println(next);
}
listInstance.forEach(System.out::println);
sql = "SELECT `id`,`name`,`email`,`birth` FROM `customers`";
List<Customer> list = getListInstance(Customer.class, sql);
list.forEach(System.out::println);
}
public <T> List<T> getListInstance(Class<T> clazz,String sql,Object ...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
ArrayList<T> alist = null;
try {
conn = JdbcUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
rs = ps.executeQuery();
//获取结果集元数据
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
alist = new ArrayList<T>();
while(rs.next()) {
T t = clazz.newInstance();
for(int i = 0;i < columnCount;i++) {
//获取列别名
String columnLabel = rsmd.getColumnLabel(i + 1);
//获取列值
Object columnValue = rs.getObject(i + 1);
//为列名为columnLabel的赋值,通过反射
Field field = clazz.getDeclaredField(columnLabel);
//防止field为私有权限
field.setAccessible(true);
field.set(t, columnValue);
}
alist.add(t);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JdbcUtils.closeResource(conn, ps, rs);
}
return alist;
}
ResultSet
查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现
ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。
ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的 hasNext() 和 next() 方法的结合体。
当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。
- 例如: getInt(1), getString(“name”)
- 注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。
ResultSetMetaData
可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
ResultSetMetaData meta = rs.getMetaData();
-
getColumnName(int column):获取指定列的名称
-
getColumnLabel(int column):获取指定列的别名
-
getColumnCount():返回当前 ResultSet 对象中的列数。
-
getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
-
getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
-
isNullable(int column):指示指定列中的值是否可以为 null。
-
isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。
获取 ResultSet 中有多少列
调用 ResultSetMetaData 的 getColumnCount() 方法
获取 ResultSet 每一列的列的别名
调用 ResultSetMetaData 的getColumnLabel() 方法