减少各个Dao类间的重复代码,有以下几种方式:
写一个DBConnectionManager,将公共的查询逻辑做成方法,将sql语句作为参数传递给方法。
public class DBConnectionManager{ static{ Class.forName("com.mysql.jdbc.Driver"); } //读操作 public static List<Map<String,Object>> selectObject(String sql, String[] params) throws Exception { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; List<Map<String,Object>>> result = new ArrayList<Map<String,Object>>>(); try { conn = DBConnectionManager.getConnection(); pstmt = conn.prepareStatement(sql); for (int i = 0; params != null && i < params.length; i++) { pstmt.setString(i + 1, params[i]); } rs = pstmt.executeQuery(); ResultSetMetaData meta = rs.getMetaData(); while (rs.next()) { Map<String,Object> columnValue = new HashMap<String,Object> int size = meta.getColumnCount(); for (int i = 1; i <= size; i++) { String columnName = meta.getColumnLabel(i); //getColumnName返回的是数据库列名,getColumnLabel如有别名将返回列的别名,否则和getColumnName相同 columnValue.add(columnName,rs.getObject(columnName)); } result.add(columnValue); } return result; } catch (Exception e) { //logger.info("Execute sql : " + sql + " fail!!!"); throw e; } finally { DBConnectionManager.free(conn, pstmt, rs); } } //增删改操作 public static void updateObject(String sql, String[] params) throws Exception { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DBConnectionManager.getConnection(); pstmt = conn.prepareStatement(sql); for (int i = 0; params != null && i < params.length; i++) { pstmt.setObject(i + 1, params[i]); } rs = pstmt.executeUpdate(); } catch (Exception e) { //logger.info("Execute sql : " + sql + " fail!!!"); throw e; } finally { DBConnectionManager.free(conn, pstmt, rs); } } //更好的做法是从数据库连接池中取链接 public static Connection getConnection(){ String dbName = "nnm5"; String passwrod = "OSSDB123"; String userName = "root"; String url = "jdbc:mysql://localhost:13306/" + dbName; Connection conn = DriverManager.getConnection(url, userName,passwrod); return conn; } public static void free(Connection conn,PreparedStatement pstmt,ResultSet rs){ if (rs != null) { try { rs.close(); } finally{ if(ps != null){ try{ ps.close(); }finally{ if(conn != null){ conn.close(); } } } } } }
上述方法不好的地方在于返回的结果是 List<Map<String,Object>>,如果希望能像ORM框架那样的返回对象,就可以实现一个RowMapper,类似于Spring中提供的SimpleJdbcTemplate。
代码中加上RowMapper也有两种方式,第一种是使用模板方式,第二种是使用策略方式。
使用模板方式的例子如下,修改上面的模板类中的方法:
public static List selectObject(String sql, String[] params) throws Exception { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; List<Map<String,Object>>> result = new ArrayList<Map<String,Object>>>(); try { conn = DBConnectionManager.getConnection(); pstmt = conn.prepareStatement(sql); for (int i = 0; params != null && i < params.length; i++) { pstmt.setString(i + 1, params[i]); } rs = pstmt.executeQuery(); List list = new ArrayList(); int index=0; while (rs.next()) { list.add(objectMapper(rs)); //传递的是每次减去一行后的结果集 index++; } return list ; } catch (Exception e) { //logger.info("Execute sql : " + sql + " fail!!!"); throw e; } finally { DBConnectionManager.free(conn, pstmt, rs); } } public abstract Object objectMapper(ResultSet rs);
具体的Dao中的代码如下:
public List getPerson(Integer id){ String sql="select id,name from person where id<?"; Object [] objs=new Object[]{id}; return super.getObject(sql,objs); //实际调用的还是该类中的objectMapper。 } public Object objectMapper(ResultSet rs){ Person person=new Person; try{ person.setId((Integer)rs.getObject(1)); person.setName((String)rs.getObject(2)); }catch(Exception e){ logger.log(e.printStackTrace()); } return person; }
使用策略模式修改模板类中的代码如下:
首先需要一个接口:
public interface RowMapper { public Object objectMapper(ResultSet rs); }
再修改模板类:
public static List selectObject(String sql, String[] params, RowMapper mapper) throws Exception { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; List<Map<String,Object>>> result = new ArrayList<Map<String,Object>>>(); try { conn = DBConnectionManager.getConnection(); pstmt = conn.prepareStatement(sql); for (int i = 0; params != null && i < params.length; i++) { pstmt.setString(i + 1, params[i]); } rs = pstmt.executeQuery(); List list = new ArrayList(); int index=0; while (rs.next()) { list.add(mapper.objectMapper(rs)); //传递的是每次减去一行后的结果集 index++; } return list ; } catch (Exception e) { //logger.info("Execute sql : " + sql + " fail!!!"); throw e; } finally { DBConnectionManager.free(conn, pstmt, rs); } }
具体的Dao中的代码:
public List getPerson(Integer id) { String sql="select id,name from person where id<?"; Object [] objs=new Object[]{id}; return mu.getObject(sql,objs,new MyRowMapper1()); } class MyRowMapper1 implements RowMapper{ public Object objectMapper(ResultSet rs) { Person person=new Person(); try{ person.setId((Integer)rs.getObject(1)); person.setName((String)rs.getObject(2)); }catch(Exception e){ logger.log(e.printStackTrace()); } return person; } }
使用JDBC的SimpleJDBCTemplate的代码:
String sql2 = "select id,tname as name,tpwd as password from tadd where tname = :tname"; RowMapper<UserBean> rw = new RowMapper<UserBean>(){ @Override public UserBean mapRow(ResultSet paramResultSet, int paramInt) throws SQLException { UserBean ub = new UserBean(); ub.setId(paramResultSet.getObject("id") + ""); ub.setName(paramResultSet.getObject("tname") + ""); ub.setPassword(paramResultSet.getObject("tpwd") + ""); return ub; } }; Map<String, String> map = new HashMap<String, String>(); map.put("tname", "p"); UserBean ub = jdbctemplate.queryForObject(sql2, map, rw); //UserBean ub = jdbctemplate.queryForObject(sql2, map, new BeanPropertyRowMapper(UserBean.class)); System.out.println(ub.getName() + "," + ub.getPassword());
queryForObject只返回一条记录,如果是多条记录应该用query方法。queryForString(String sql,String.class)将返回字符串型的结果。如果没有对应的javabean,可以用queryForMap和queryForList方法。queryForMap返回一条记录,queryForList返回多条记录。
如果希望能够取得插入记录的主键值,可以调用回调函数,也可以在回调函数中对connection做更多的处理。
static Integer id=0; public static int getId(final Person person) { JdbcTemplate jdbcTemplate=new JdbcTemplate(JDBCUtils.getDataSource()); jdbcTemplate.execute(new ConnectionCallback(){ //传递的参数为Connection conn,自己可以在conn内写希望完成的功能 public Object doInConnection(Connection conn) throws SQLException,DataAccessException{ String sql="insert into person(name) values (?)"; PreparedStatement ps=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//返回所插入数据的主键 for(int i=0;i<10;i++){ ps.setString(1, person.getName()); ps.addBatch(); //批处理,将SQL语句进行打包 } //ps.executeUpdate(); ps.executeBatch(); //没有这一行是不会插入数据的 ResultSet rs=ps.getGeneratedKeys(); while(rs.next()) id=rs.getInt(1); return id; } }); return id; }
SimpleJdbcTemplate里面封装了NamedJdbcTemplate,NamedJdbcTemplate里面又包含JdbcTemplate,增加了对泛型和可变长度参数的支持。从Spring 3.1开始,JdbcTemplate和NamedParameterJdbcTemplate提供了SimpleJdbcTemplate的功能。SimpleJdbcTemplate被标注为过时,使用JdbcTemplate和NamedParameterJdbcTemplate即可。
使用JDBCTemplate的KeyHolder获取新插入数据的主键:
String sql="insert into person(name) values (:name)"; Map map = new HashMap(); map.put(":tname","add");
//Person p = new Person();
//SqlParamterSource ps = new BeanPropertySqlParamterSource(p);
KeyHolder keyHolder = new GeneratedKeyHolder(); jdbctemplate.update(sql, map, keyHolder ); int id = keyHolder.getKey().intValue(); //单主键的情况 Map map = keyHolder.getKeys(); //混合主键的情况
如果想调用NamedJdbcTemplate中的方法,可以使用jdbctemplate.getNamedJdbcTemplate()。
使用SimpleJdbcTemplate的例子:
@Override public void delete(int id) { String sql = "delete from user where id=?"; getSimpleJdbcTemplate().update(sql, id); } @Override public User findById(int id) { String sql = "select * from user where id=?"; return getSimpleJdbcTemplate().queryForObject(sql, ParameterizedBeanPropertyRowMapper.newInstance(User.class), id); // 下面的方法只能返回一列,所以行不通 // return getSimpleJdbcTemplate().queryForObject(sql, User.class, id); } @Override public int findByName(String name){ String sql = "select id from user where name=?"; return getSimpleJdbcTemplate().queryForObject(sql, Integer.class, name); // Integer.class 改成int.class 不行 // 貌似只能用包装类 } @Override public List<User> findAll() { String sql = "select * from user"; return getSimpleJdbcTemplate().query(sql, ParameterizedBeanPropertyRowMapper.newInstance(User.class)); } @Override public int count() { String sql = "select count(*) from user"; return getSimpleJdbcTemplate().queryForInt(sql); } @Override public void batchInsert(List<User> users) { String sql = "insert into user(id,name)values(?,?)"; List<Object[]> parameters = new ArrayList<Object[]>(); for (User u : users) { parameters.add(new Object[] { u.getId(), u.getName() }); } getSimpleJdbcTemplate().batchUpdate(sql, parameters); }