千家信息网

Spring JDBC 访问数据库

发表于:2024-10-05 作者:千家信息网编辑
千家信息网最后更新 2024年10月05日,Spring JDBC是Spring所提供的持久层技术,它以一种更直接、更简单的方式使用JDBC API。在Spring JDBC里,用户仅需要做那些必不可杀的事儿,而将资源获取、Statement创
千家信息网最后更新 2024年10月05日Spring JDBC 访问数据库

Spring JDBC是Spring所提供的持久层技术,它以一种更直接、更简单的方式使用JDBC API。在Spring JDBC里,用户仅需要做那些必不可杀的事儿,而将资源获取、Statement创建、异常处理、资源释放等繁杂的工作交给Spring。

虽然ORM的框架已经很成熟,但是JDBC灵活直接的特性依旧让它有自己的用武之地。

本节的主要内容:使用JdbcTemplate模板类进行CRUD数据操作、BLOB和CLOB类型数据的操作,支持命名参数绑定NamedParameterJdbcTemplate模拟类的使用。

1.在DAO中使用JdbcTemplate

一般情况下,在XML中配置好JdbcTemplate,然后在DAO中注入即可

Spring配置文件中定义的JdbcTemplate并注入DAO中

                                                                               
//@Repository声明一个DAO@Repository    public class AdminDao implements IAdminDao { private static Logger logger=Logger.getLogger(AdminDao.class); private static final long serialVersionUID = 1L; //@Autowired注入JdbcTemplate实例声明一个DAO @Autowired private JdbcTemplate jdbcTemplate; @Override public Admin getAdminByNamAndPassword(String adminId, String password) {  // TODO Auto-generated method stub  String sql="select adminId,adminName,adminPassword,adminHead,MAX(FROM_UNIXTIME(lastvisittime,'%Y-%m-%d %H:%m:%S')),lastvisitip from zzia_admin left join zzia_login_log on adminId=userId "    + "where adminName='"+adminId+"' and adminPassword='"+password+"' ";  final Admin a=new Admin();  this.jdbcTemplate.query(sql, new RowCallbackHandler() {      @Override   public void proce***ow(ResultSet rs) throws SQLException {    // TODO Auto-generated method stub    a.setAdminId(rs.getInt(1));    a.setAdminName(rs.getString(2));    a.setAdminPassword(rs.getString(3));    a.setAdminHead(rs.getString(4));    a.setLastVisitTime(rs.getString(5));    a.setLastVisitIp(rs.getString(6));   }  });  return a; }

2.基本的数据操作

数据的增删查改以及存储过程调用是最基本的数据库操作,JdbcTemplate提供了众多的方法,通过JdbcTemplate用户可以用简单的方法完成这些数据操作

2.1更改数据

JdbcTemplate提供了若干update()方法,允许用户对数据表记录进行更改和删除操作

update示例:

public class TestJdbcTemplate { ...//这里省略jdbcTemplate的定义 private static final String sql = "insert into jf_user(user_name,user_pwd,user_age) values(?,?,?)"; public static void addUser(User user) {  Object[] params = new Object[]{user.getUsername(),user.getUserpwd(),user.getUserage()};  int update = jdbcTemplate.update(sql, params);  if(update > 0){   System.out.println("插入成功");  } }}

2.2、返回数据库的表自增主键值

用户经常使用数据的子增字段作为表主键,即主键值不在应用层产生,而是在新增记录时,由数据库产生。这样,应用层在保存对象前并不知道对象主键值,而只有在保存数据后才能从数据库中返回主键值。在很多情况下,需要获取新对象持久化后的主键值。在Hibernate、JPA等ORM框架中,新对象在持久化后,主键值会自动绑定到对象上,给程序的开发带来了很多方便。

Spring提供了一个可以返回新增记录对应主键值的方法。int update(PreparedStatementCreator psc,KeyHolder generatedKeyHolder);org.springframework.jdbc.support.KeyHolder是一个回调接口,spring使用它保存新增记录对应的主键。Spring为KeyHolder接口指代了一个通用的实现类GeneratedKeyHolder,该类返回新增记录时的自增长主键值。假设希望在新增对象后,将主键值加载到对象中,则代码示例

public static void addUserWithKeyHolder(final User user){  final String sql = "insert into jf_user(user_name,user_pwd,user_age) values(?,?,?)";  KeyHolder keyHolder = new GeneratedKeyHolder();  jdbcTemplate.update(new PreparedStatementCreator() {      @Override   public PreparedStatement createPreparedStatement(Connection con) throws SQLException {    PreparedStatement ps = con.prepareStatement(sql);    ps.setString(1, user.getUsername());    ps.setString(2, user.getUserpwd());    ps.setString(3, user.getUserage());    return ps;   }  }, keyHolder);  user.setSerialNo(keyHolder.getKey().intValue()); }

如果数据库并发率比较高,如在插入记录后执行查询主键之前,数据库又执行了如果条插入记录,那么通过数据查询语句新增主键值将会只返回最后一条插入的主键值。因此,使用查询语句获取的主键值是不安全的,这也是为什么有些数据库(如Oracle)故意不提供自增键,而是只提供序列的原因,序列强制要求用户在新增记录前,先获取主键值。Oracle通过SELECT .nextval FROM DUAL获取序列的下一个值。

2.3、批量更改数据

如果需要一次性插入或更新多条记录,可以使用jdbcTemplate的batchUpdate方法

batchUpdate示例:

public static void addUsers(final List users){  final String sql = "insert into jf_user(user_name,user_pwd,user_age) values(?,?,?)";  jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {   @Override   public void setValues(PreparedStatement ps, int i) throws SQLException {    // TODO Auto-generated method stub    User user = users.get(i);    ps.setString(1, user.getUsername());    ps.setString(2, user.getUserpwd());    ps.setString(3, user.getUserage());   }      @Override   public int getBatchSize() {    // TODO Auto-generated method stub    return users.size();   }  }); }

2.4、查询数据

2.4.1、使用RowCallbackHandler处理结果集

Spring提供了org.springframework.jdbc.core.RowCallbackHandler回调接口,通过该接口可以定义如何从结果集中获取数据。

RowCallbackHandler示例:

/**  * @Title: getUserBySerialNo  * @Description: TODO 获取单个结果集 * @param @param serialNo * @param @return    设定文件  * @return User    返回类型  * @throws  */  public User getUserBySerialNo(final int serialNo){  String sql = "SELECT serial_no,user_name,user_pwd,user_age FROM jf_user.jf_users WHERE serial_no = ?";  final User user = new User();  jdbcTemplate.query(sql, new Object[]{serialNo},new RowCallbackHandler() {      @Override   public void proce***ow(ResultSet rs) throws SQLException {    user.setSerialNo(serialNo);    user.setUsername(rs.getString("user_name"));    user.setUserpwd(rs.getString("user_pwd"));    user.setUserage(rs.getString("user_age"));   }  });  return user; }  /**  * @Title: getUsers  * @Description: TODO 获取多个结果集 * @param @param fromSerialNo * @param @param toSerialNo * @param @return    设定文件  * @return List    返回类型  * @throws  */  public List getUsers(final int fromSerialNo,final int toSerialNo){  String sql = "SELECT serial_no,user_name,user_pwd,user_age FROM jf_user.jf_users WHERE serial_no between ? and ?";  final List users = new ArrayList<>();  jdbcTemplate.query(sql, new Object[]{fromSerialNo,toSerialNo}, new RowCallbackHandler() {      @Override   public void proce***ow(ResultSet rs) throws SQLException {    // TODO Auto-generated method stub    User user = new User();    user.setSerialNo(rs.getInt("serial_no"));    user.setUsername(rs.getString("user_name"));    user.setUserpwd(rs.getString("user_pwd"));    user.setUserage(rs.getString("user_age"));    users.add(user);   }  });  return users; }

2.4.2、使用RowMapper处理结果集

Spring也提供了一个和RowCallbackHandler功能类似的RowMapper接口,它也可以使用RowMapper定义结果集逻辑映射,在结果集为多行记录时,该接口更容易使用。

RowMapper代码示例

/**  * @Title: getUsersOnRowMapper  * @Description: TODO 利用RowMapper映射多行数据 * @param @param fromSerialNo * @param @param toSerialNo * @param @return    设定文件  * @return List    返回类型  * @throws  */  public List getUsersOnRowMapper(final int fromSerialNo,final int toSerialNo){  String sql = "SELECT serial_no,user_name,user_pwd,user_age FROM jf_user.jf_users WHERE serial_no between ? and ?";  return jdbcTemplate.query(sql, new Object[]{fromSerialNo,toSerialNo},new RowMapper(){   @Override   public User mapRow(ResultSet rs, int rowNum) throws SQLException {    // TODO Auto-generated method stub    User user = new User();    user.setSerialNo(rs.getInt("serial_no"));    user.setUsername(rs.getString("user_name"));    user.setUserpwd(rs.getString("user_pwd"));    user.setUserage(rs.getString("user_age"));    return user;   }  }); }

2.5、查询单值数据

如果查询的结果集仅有一个值,如SELECT COUNT(*) FROM jf_users等,就可以使用更简单的方式获取结果的值。JdbcTemplate为获取结果集中的单值数据提供了3组方法,分别用于获取int、long的单值,其他类型的单值以Object类型返回

2.6、调用存储过程

JdbcTemplate提供了2个调用存储过程的接口方法:

T execute(String callString,CallableStatementCallback action);

T execute(CallableStatementCreator csc,CallableStatementCallback cs);

调用存储过程示例:

CREATE PROCEDURE P_GET_VIEW_POINT_NUM(IN in_serialNO,INT,OUT out_num INT)BEGIN    SELECT COUNT(*) INTO out_num FROM jf_user WHERE serialNO = in_serialNo;END;
/**  * @Title: getUserCounts  * @Description: TODO JdbcTemplate调用存储过程 * @param @param serailNo * @param @return    设定文件  * @return int    返回类型  * @throws  */  public int getUserCounts(final int serailNo){  String sql = "{call P_GET_VIEW_POINT_NUM(?,?)}";  String execute = jdbcTemplate.execute(sql, new CallableStatementCallback() {   @Override   public Object doInCallableStatement(final CallableStatement cs) throws SQLException, DataAccessException {    // TODO Auto-generated method stub    cs.setInt(1, serailNo);    cs.registerOutParameter(2, Types.INTEGER);    cs.execute();    return cs.getInt(2);   }  });  return Integer.valueOf(execute); }
0