任何一个一个程序员都离不开与数据库打交道,尤其是我们这些开发后台的.今天,小哥给大家整理了一些java中JDBC的操作管理方法;
主要有如下内容;
1,解决sql注入问题,并抽取工具类;实现增删改查;
a)sql注入
conn = DriverManager.getConnection(URL, NAME, PASSWORD); //创建sql语句 String sql="select *from user where name='"+name+"'"+"password'"; //创建statement与数据库交互 st = conn.createStatement(); //执行sql语句并返回结果 rs = st.executeQuery(sql); if(rs.next()){ System.out.println("操作成功"); }
由于字符串拼接组成的sql语句,导致statement在某些时候会出现问题;
比如在传入的那name和password中有关键字的情况;
1,当某人得知你的用户名时,无需知道密码即可直接登录网站,
如;我传入的用户名是:aaa ' or 1=1
或者用户名是aaa -- (后面有一个空格)
这两种情况都会发生sql的注入问题.
解决办法是,使用preparedstatement采用占位符的方式解决;
package com.test03; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.pierce.domain.Person; /** * 使用最初始的方法 * * @author Administrator * */ public class Test01 { /* * 准备数据库连接的工作 */ // 数据库地址; private static final String URL = "jdbc:mysql://localhost:3306/table"; // 用户名: private static final String NAME = "root"; // 密码; private static final String PASSWORD = ""; // 驱动; private static final String DRIVE = "com.mysql.jdbc.Driver"; // 程序加载时,加载驱动 static { try { Class.forName(DRIVE); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 相数据库中插入一条信息; private static void insert(Person p) { // 创建连接 Connection conn = null; PreparedStatement ps = null; try { conn = DriverManager.getConnection(URL, NAME, PASSWORD); // 创建sql语句 String sql = "insert into person (name,age,description) values(?,?,?)"; // 创建statement//解析sql语句 ps = conn.prepareStatement(sql); // ps.setString(1, p.getName()); ps.setInt(2, p.getAge()); ps.setString(3, p.getDescription()); // 对数据库进行操作; ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } ps = null; } } } public static void update(Person p) { Connection conn = null; PreparedStatement ps = null; // 获取连接 try { conn = DriverManager.getConnection(URL, NAME, PASSWORD); // 创建一个sql语句 String sql = "update person set name=?,age=?,description=? where id=?"; // 获取statement用于与数据库交互操作; ps = conn.prepareStatement(sql); // 将数据存入到statement中; ps.setString(1, p.getName()); ps.setInt(2, p.getAge()); ps.setString(3, p.getDescription()); ps.setInt(4, p.getId()); // 执行sql语句 ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } ps = null; } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } } public static void delete(int id) { Connection conn = null; PreparedStatement ps = null; // 创建连接; try { conn = DriverManager.getConnection(URL, NAME, PASSWORD); // 创建sql语句 String sql = "delete from person where id=?"; // 创建statement对象,与数据库进行交互; ps = conn.prepareStatement(sql); // 设置ps属性值 ps.setInt(1, id); // 执行sql语句 ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } ps = null; } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } } public static Person findById(int id) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; // 建立连接 try { conn = DriverManager.getConnection(URL, NAME, PASSWORD); // 创建sql String sql = "select name,age,description from person where id=?"; // 创建statement对象,与数据库交互 ps = conn.prepareStatement(sql); // 设置ps的属性值 ps.setInt(1, id); // 执行sql语句将数据返回到一个结果集 rs = ps.executeQuery(); // 创建一个person对象 Person p = null; // 遍历结果集 if (rs.next()) { p = new Person(); p.setId(id); p.setName(rs.getString(1)); p.setAge(rs.getInt(2)); p.setDescription(rs.getString(3)); } return p; } catch (SQLException e) { e.printStackTrace(); } return null; } public static List<Person> findAll() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; // 创建连接 try { conn = DriverManager.getConnection(URL, NAME, PASSWORD); // 创建sql语句 String sql = "select id,name,age,description from person"; // 创建statement对象,实现与数据库的交互 ps = conn.prepareStatement(sql); // 设置ps的属性值(略,直接执行sql语句即可) // 执行sql语句,返回一个结果集; rs = ps.executeQuery(); // 创建一个lsit集合,用于存储数据 List<Person> list = new ArrayList<Person>(); Person p = null; // 遍历rs结果集 while (rs.next()) { p = new Person(); p.setId(rs.getInt(1)); p.setName(rs.getString(2)); p.setAge(rs.getInt(3)); p.setDescription(rs.getString(4)); list.add(p); } return list; } catch (SQLException e) { e.printStackTrace(); } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null; } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } ps = null; } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } return null; } public static void main(String[] args) { // Person p=new Person(5,"张三",21,"风流倜傥"); // insert(p); // update(p); // delete(10); // Person p = findById(7); // System.out.println(p); List<Person> persons = findAll(); for (Person person : persons) { System.out.println(person); } } }
上面呢,是使用了preparedstement的类,采用占位符的方式,其原理是,preparedstatement现将sql语句进行预编译,预编译之后,您传进来的东西都会作为一个字符串处理,就算里面有
关键字,也不会识别,这样就彻底解决了注入的问题;
我们发现,上面的代码重复的内容太多,并且,我们的数据库连接都是写死的,这样很不利于日后的项目维护;
所有,我接下来做两件事,:
1,抽取出一个工具类,将数据初始化工作,一并交给工具类;
工具类如下:
public class DBUtils { //私有化,不允许创建对象 private DBUtils() {} //准备数据 //数据库地址; private static final String URL; //用户名: private static final String NAME; //密码; private static final String PASSWORD; //驱动; private static final String DRIVE; //读取配置文件 private static final ResourceBundle rb=ResourceBundle.getBundle("com.test03.db-config"); //程序加载时,加载驱动,加载准备属性值 static { DRIVE=rb.getString("driver"); URL=rb.getString("url"); NAME=rb.getString("name"); PASSWORD=rb.getString("password"); try { Class.forName(DRIVE); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //创建获取连接的工具 public static Connection getConnection(){ Connection conn=null; try { conn = DriverManager.getConnection(URL, NAME, PASSWORD); } catch (SQLException e) { e.printStackTrace(); } return conn; } //定义一个关闭资源的方法; public static void close(ResultSet rs,PreparedStatement ps, Connection conn){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs=null; } if(ps!=null){ try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } ps=null; } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn=null; } } }
配置文件内容如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/table
name=root
password=
2)抽取出模版类:
public class JDBCTemplete { private JDBCTemplete() {} /** * * @param sql * @param args * @return */ public static int update(String sql,Object...args){ Connection conn=null; PreparedStatement ps = null; try { conn = DBUtils.getConnection(); ps = conn.prepareStatement(sql); if(args!=null){ for (int i = 0; i < args.length; i++) { ps.setObject(i+1, args[i]); } } return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); return -1; }finally{ DBUtils.close(null, ps, conn); } } public static Object query(String sql,ResultSetHandler handler,Object...args){ Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn =DBUtils.getConnection(); ps = conn.prepareStatement(sql); if(args!=null){ for (int i = 0; i < args.length; i++) { ps.setObject(i+1, args[i]); } } rs = ps.executeQuery(); return handler.doHandler(rs); } catch (SQLException e) { e.printStackTrace(); }finally{ DBUtils.close(rs, ps, conn); } return null; } }
这里的模版类涉及到了可变参数,至于可变参数的提取原理,我们下期在解释;
public class PersonDaoImpl { //相数据库中插入一条信息; public void insert(Person p) { String sql="insert into person (name,age,description)values(?,?,?)"; JDBCTemplete.update(sql, p.getName(),p.getAge(),p.getDescription()); } public void update(Person p){ String sql="update person set name=?,age=?,description=? where id=?"; JDBCTemplete.update(sql,p.getName(),p.getAge(),p.getDescription(),p.getId()); } public void delete(int id){ String sql="delete from person where id=?"; JDBCTemplete.update(sql, id); } public Person findById(final int id){ String sql="select name,age,description from person where id=?"; return (Person)JDBCTemplete.query(sql, new ResultSetHandler() { @Override public Object doHandler(ResultSet rs) throws SQLException { Person p=null; if(rs.next()){ p=new Person(); p.setId(id); p.setName(rs.getString(1)); p.setAge(rs.getInt(2)); p.setDescription(rs.getString(3)); } return p; } }, id); } @SuppressWarnings("unchecked") public List<Person> findAll(){ String sql="select id,name,age,description from person"; return (List<Person>)JDBCTemplete.query(sql, new ResultSetHandler() { @Override public Object doHandler(ResultSet rs) throws SQLException { List<Person>list=new ArrayList<Person>(); Person p=null; while(rs.next()){ p=new Person(); p.setId(rs.getInt(1)); p.setName(rs.getString(2)); p.setAge(rs.getInt(3)); p.setDescription(rs.getString(4)); list.add(p); } return list; } }); } }
PersonDao的实现类,注意这里的查询方法中有一个结果集的接口,使用匿名对象,实现结果集的接收工作;
好了,今天先理到这,下一期,我会给大家介绍如下内容:
2,使用dbutils工具类和连接池技术(c3p0,druid),降低数据库访问过程中性能消耗问题;
3,介绍dbutils工具类中9大结果集处理器的使用;
4,介绍mysql中的事物管理.