jdbc-增强
MySQL执行预编译分为如三步:1、执行预编译语句;2.设置变量;3.执行语句
如果需要再次执行,那么就不再需要第一步,即不需要再编译语句了:1.设置变量;2.执行语句;
防sql注入
public class Demo { private String name = "ericdfd' OR 1=1 -- "; //private String name = "eric"; private String password = "123456"; /** * Statment存在sql被注入的风险 */ @Test public void testByStatement(){ Connection conn = null; Statement stmt = null; ResultSet rs = null; try { conn = JdbcUtil.getConnection(); stmt = conn.createStatement(); String sql = "SELECT * FROM user WHERE NAME='"+name+"' AND PASSWORD='"+password+"'"; rs = stmt.executeQuery(sql); if(rs.next()){ System.out.println("登录成功"); }else{ System.out.println("登录失败"); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt ,rs); } } /** * PreparedStatement可以有效地防止sql被注入 */ @Test public void testByPreparedStatement(){ Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtil.getConnection(); String sql = "SELECT * FROM user WHERE NAME=? AND PASSWORD=?"; stmt = conn.prepareStatement(sql); stmt.setString(1, name); stmt.setString(2, password); rs = stmt.executeQuery(); if(rs.next()){ System.out.println("登录成功"); }else{ System.out.println("登录失败"); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt ,rs); } } }
批处理
public class Admin { private String userName; private String pwd; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }
public class AdminDao { private Connection con; private PreparedStatement pstmt; private ResultSet rs; public void save(List<Admin> list) { String sql = "INSERT INTO admin(userName,pwd) values(?,?)"; try { con = JdbcUtil.getConnection(); pstmt = con.prepareStatement(sql); for (int i=0; i<list.size(); i++) { Admin admin = list.get(i); pstmt.setString(1, admin.getUserName()); pstmt.setString(2, admin.getPwd()); pstmt.addBatch(); if (i % 5 == 0) { pstmt.executeBatch(); pstmt.clearBatch(); } } pstmt.executeBatch(); pstmt.clearBatch(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.close(con, pstmt, rs); } } }
public class App { @Test public void testBatch() throws Exception { List<Admin> list = new ArrayList<>(); for (int i=1; i<21; i++) { Admin admin = new Admin(); admin.setUserName("Jack" + i); admin.setPwd("888" + i); list.add(admin); } AdminDao dao = new AdminDao(); dao.save(list); } }
Jdbc事务
在默认情况下,每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。
在执行SQL语句之前,先执行strat transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所做出的影响会持久化到数据库中。或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤消了。
Connection的三个方法与事务相关:
(1)setAutoCommit(boolean):设置是否为自动提交事务,如果true(默认值就是true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务。
如果设置false,那么就相当于开启了事务了;con.setAutoCommit(false)表示开启事务。
(2)commit():提交结束事务;con.commit();表示提交事务。
(3)rollback():回滚结束事务。con.rollback();表示回滚事务。
public class TransAccount { // 全局参数 private Connection con; private PreparedStatement pstmt; // 1. 转账,没有使用事务 @Test public void trans() { String sql_zs = "UPDATE account SET money=money-1000 WHERE account_name ='张三';"; String sql_ls = "UPDATE account SET money1=money+1000 WHERE account_name='李四';"; try { con = JdbcUtil.getConnection(); //con.setAutoCommit(true); /*** 第一次执行SQL ***/ pstmt = con.prepareStatement(sql_zs); pstmt.executeUpdate(); /*** 第二次执行SQL ***/ pstmt = con.prepareStatement(sql_ls); pstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtil.close(con, pstmt); } } // 2. 转账,使用事务 @Test public void trans2() { String sql_zs = "UPDATE account SET money=money-1000 WHERE account_name='张三'"; String sql_ls = "UPDATE account SET money=money+1000 WHERE account_name ='李四'"; try { con = JdbcUtil.getConnection(); // 设置事务为手动提交 con.setAutoCommit(false); /*** 第一次执行SQL ***/ pstmt = con.prepareStatement(sql_zs); pstmt.executeUpdate(); /*** 第二次执行SQL ***/ pstmt = con.prepareStatement(sql_ls); pstmt.executeUpdate(); } catch (Exception e) { try { // 出现异常,需要回滚事务 con.rollback(); } catch (SQLException e1) { } e.printStackTrace(); } finally { try { // 所有的操作执行成功, 提交事务 con.commit(); JdbcUtil.close(con, pstmt); } catch (SQLException e) { } } } // 3. 转账,使用事务, 回滚到指定的代码段 @Test public void trans3() { // 定义个标记 Savepoint sp = null; // 第一次转账 String sql_zs1 = "UPDATE account SET money=money-1000 WHERE account_name ='张三';"; String sql_ls1 = "UPDATE account SET money=money+1000 WHERE account_name ='李四';"; // 第二次转账 String sql_zs2 = "UPDATE account SET money=money-500 WHERE account_name ='张三';"; String sql_ls2 = "UPDATE1 account SET money=money+500 WHERE account_name ='李四';"; try { con = JdbcUtil.getConnection(); // 默认开启的隐士事务 con.setAutoCommit(false); // 设置事务手动提交 /*** 第一次转账 ***/ pstmt = con.prepareStatement(sql_zs1); pstmt.executeUpdate(); pstmt = con.prepareStatement(sql_ls1); pstmt.executeUpdate(); // 回滚到这个位置? sp = con.setSavepoint(); /*** 第二次转账 ***/ pstmt = con.prepareStatement(sql_zs2); pstmt.executeUpdate(); pstmt = con.prepareStatement(sql_ls2); pstmt.executeUpdate(); } catch (Exception e) { try { // 回滚 (回滚到指定的代码段) con.rollback(sp); } catch (SQLException e1) { } e.printStackTrace(); } finally { try { // 提交 con.commit(); } catch (SQLException e) { } JdbcUtil.close(con, pstmt); } } }
BeanUtils组件
1 public class Admin { 2 3 private int id; 4 private String userName; 5 private int age; 6 7 public int getId() { 8 return id; 9 } 10 public void setId(int id) { 11 this.id = id; 12 } 13 public String getUserName() { 14 return userName; 15 } 16 public void setUserName(String userName) { 17 this.userName = userName; 18 } 19 public int getAge() { 20 return age; 21 } 22 public void setAge(int age) { 23 this.age = age; 24 } 25 26 @Override 27 public String toString() { 28 return "Admin{" + 29 "id=" + id + 30 ", userName='" + userName + '\'' + 31 ", age=" + age + 32 '}'; 33 } 34 }
1 public class App { 2 3 @Test 4 public void test() throws Exception { 5 6 Admin admin = new Admin(); 7 // 对象属性的拷贝 8 BeanUtils.copyProperty(admin, "userName", "jack"); 9 BeanUtils.setProperty(admin, "age", 18); 10 System.out.println(admin.toString()); 11 12 // 对象之间的拷贝 13 Admin newAdmin = new Admin(); 14 BeanUtils.copyProperties(newAdmin, admin); 15 System.out.println(newAdmin.toString()); 16 17 // Map数据拷贝到对象 18 Admin adminMap = new Admin(); 19 Map<String,Object> map = new HashMap<>(); 20 map.put("userName", "Jerry"); 21 map.put("age", 29); 22 BeanUtils.populate(adminMap, map); 23 System.out.println(adminMap.toString()); 24 25 } 26 }
元数据
元数据:数据库、表、列的定义信息。
DataBaseMetaData对象:Connection.getMetaData() 获得代表Connection元数据的DataBaseMetaData对象。
常用方法:
getURL():返回一个String类对象,代表数据库的URL
getUserName():返回连接当前数据库管理系统的用户名
getDatabaseProductName():返回数据库的产品名称
getDatabaseProductVersion():返回数据库的版本号
getDriverName():返回驱动驱动程序的名称
getDriverVersion():返回驱动程序的版本号
isReadOnly():返回一个boolean值,指示数据库是否只允许读操作
ParameterMetaData对象:PreparedStatement.getParameterMetaData()获得代表PreparedStatement元数据的ParameterMetaData对象
常用方法:
getParameterCount() 获得指定参数的个数
getParameterType(int param) 获得指定参数的sql类型
ResultSetMetaData对象:ResultSet.getMetaData()获得代表ResultSet对象元数据的ResultSetMetaData对象
常用方法:
getColumnCount() 返回resultset对象的列数
getColumnName(int column) 获得指定列的名称
getColumnTypeName(int column) 获得指定列的类型
1 public class App { 2 3 // 1. 数据库元数据 4 @Test 5 public void testDB() throws Exception { 6 7 Connection conn = JdbcUtil.getConnection(); 8 // 获取数据库元数据 9 DatabaseMetaData metaData = conn.getMetaData(); 10 System.out.println(metaData.getUserName()); 11 System.out.println(metaData.getURL()); 12 System.out.println(metaData.getDatabaseProductName()); 13 } 14 15 // 2. 参数元数据 16 @Test 17 public void testParams() throws Exception { 18 19 Connection conn = JdbcUtil.getConnection(); 20 String sql = "select * from account where account_name=?"; 21 PreparedStatement pstmt = conn.prepareStatement(sql); 22 // 参数元数据 23 ParameterMetaData metaDate = pstmt.getParameterMetaData(); 24 // 获取参数的个数 25 int count = metaDate.getParameterCount(); 26 System.out.println(count); 27 } 28 29 // 3. 结果集元数据 30 @Test 31 public void testRs() throws Exception { 32 String sql = "select * from account "; 33 Connection conn = JdbcUtil.getConnection(); 34 PreparedStatement pstmt = conn.prepareStatement(sql); 35 ResultSet rs = pstmt.executeQuery(); 36 // 得到结果集元数据(目标:通过结果集元数据,得到列的名称) 37 ResultSetMetaData metaData = rs.getMetaData(); 38 while (rs.next()) { 39 // 获取列的个数 40 int count = metaData.getColumnCount(); 41 // 遍历,获取每一列的列的名称 42 for (int i=0; i<count; i++) { 43 // 得到列的名称 44 String columnName = metaData.getColumnName(i + 1); 45 // 获取每一行的每一列的值 46 Object columnValue = rs.getObject(columnName); 47 System.out.print(columnName + "=" + columnValue + ","); 48 } 49 System.out.println(); 50 } 51 } 52 }
1 public class Admin { 2 3 private int id; 4 private String username; 5 private String pwd; 6 7 public String getPwd() { 8 return pwd; 9 } 10 public void setPwd(String pwd) { 11 this.pwd = pwd; 12 } 13 public int getId() { 14 return id; 15 } 16 public void setId(int id) { 17 this.id = id; 18 } 19 public String getUsername() { 20 return username; 21 } 22 public void setUsername(String username) { 23 this.username = username; 24 } 25 @Override 26 public String toString() { 27 return "Admin [id=" + id + ", pwd=" + pwd + ", username=" + username 28 + "]"; 29 } 30 }
1 public class BaseDao { 2 3 // 初始化参数 4 private Connection con; 5 private PreparedStatement pstmt; 6 private ResultSet rs; 7 8 /** 9 * 更新的通用方法 10 */ 11 public void update(String sql,Object[] paramsValue){ 12 13 try { 14 con = JdbcUtil.getConnection(); 15 pstmt = con.prepareStatement(sql); 16 int count = pstmt.getParameterMetaData().getParameterCount(); 17 if (paramsValue != null && paramsValue.length > 0) { 18 for(int i=0;i<count;i++) { 19 pstmt.setObject(i+1, paramsValue[i]); 20 } 21 } 22 pstmt.executeUpdate(); 23 } catch (Exception e) { 24 throw new RuntimeException(e); 25 } finally { 26 JdbcUtil.close(con, pstmt); 27 } 28 } 29 30 /** 31 * 查询的通用方法 32 */ 33 public <T> List<T> query(String sql, Object[] paramsValue, Class<T> clazz){ 34 35 try { 36 List<T> list = new ArrayList<>(); 37 T t; 38 con = JdbcUtil.getConnection(); 39 pstmt = con.prepareStatement(sql); 40 if (paramsValue != null && paramsValue.length > 0) { 41 for (int i=0; i<paramsValue.length; i++) { 42 pstmt.setObject(i+1, paramsValue[i]); 43 } 44 } 45 rs = pstmt.executeQuery(); 46 ResultSetMetaData rsmd = rs.getMetaData(); 47 int columnCount = rsmd.getColumnCount(); 48 while (rs.next()) { 49 t = clazz.newInstance(); 50 for (int i=0; i<columnCount; i++) { 51 String columnName = rsmd.getColumnName(i + 1); 52 Object value = rs.getObject(columnName); 53 BeanUtils.copyProperty(t, columnName, value); 54 } 55 list.add(t); 56 } 57 return list; 58 } catch (Exception e) { 59 throw new RuntimeException(e); 60 } finally { 61 JdbcUtil.close(con, pstmt, rs); 62 } 63 } 64 }
1 public class AdminDao extends BaseDao { 2 3 // 删除 4 public void delete(int id) { 5 String sql = "delete from admin where id=?"; 6 Object[] paramsValue = {id}; 7 super.update(sql, paramsValue); 8 } 9 10 // 插入 11 public void save(Admin admin) { 12 String sql = "insert into admin (userName,pwd) values (?,?)"; 13 Object[] paramsValue = {admin.getUsername(),admin.getPwd()}; 14 super.update(sql, paramsValue); 15 } 16 17 // 查询全部 18 public List<Admin> getAll(){ 19 String sql = "select * from admin"; 20 List<Admin> list = super.query(sql, null, Admin.class); 21 return list; 22 } 23 24 // 根据条件查询(主键) 25 public Admin findById(int id){ 26 String sql = "select * from admin where id=?"; 27 List<Admin> list = super.query(sql, new Object[]{id}, Admin.class); 28 return (list!=null&&list.size()>0) ? list.get(0) : null; 29 } 30 }
1 public class MainTest { 2 3 @Test 4 public void testUpdate() throws Exception { 5 AdminDao adminDao = new AdminDao(); 6 adminDao.delete(2); 7 Admin admin = new Admin(); 8 admin.setUsername("test"); 9 admin.setPwd("test"); 10 adminDao.save(admin); 11 } 12 13 @Test 14 public void testQuery() throws Exception { 15 AdminDao adminDao = new AdminDao(); 16 List<Admin> list = adminDao.getAll(); 17 System.out.println(list); 18 Admin admin = adminDao.findById(3); 19 System.out.println(admin); 20 } 21 }