Spring JDBC 访问数据库
admin
2023-06-08 13:01:44
0

    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()方法,允许用户对数据表记录进行更改和删除操作

        Spring JDBC 访问数据库    

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);

Spring JDBC 访问数据库

调用存储过程示例:

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);
 }

相关内容

热门资讯

神二十三发射任务将创下多个“首... 神舟二十三号即将发射,现场各项准备工作如何?凤凰卫视特派记者孙伟健从酒泉卫星发射中心发回现场报道。
山西留神峪煤矿事故调查:写满安... 5月22日19时29分,山西沁源的暮色尚未完全降临,有着45年开矿历史的通洲集团留神峪煤矿,骤然迎来...
从狮子山下,奔赴星辰,东方之珠... 原标题:从狮子山下,奔赴星辰——香港热议载荷专家黎家盈逐梦太空 23日上午,神舟二十三号载人飞行任务...
选购激光熔覆设备:五个关键要点... 在工程建设、大型装备维护等领域,激光熔覆修复技术以其高精度、低热影响的特点,正成为关键零部件延寿再制...
NASA卫星发布其迄今最完整系... IT之家 5 月 24 日消息,美国国家航空航天局的系外行星探测卫星凌日系外行星巡天卫星(TESS)...
机器人成文博会顶流:AI+文化... 5月21日至25日,第二十二届中国(深圳)国际文化产业博览交易会(文博会)在深圳国际会展中心举行,这...
神舟二十三号瞄准北京时间今日2... 5月23日,神舟二十三号航天员朱杨柱(中)、张志远(右)、黎家盈在酒泉卫星发射中心问天阁与媒体记者集...
一文读懂:美伊协议谈得怎么样? 新华社北京5月24日电 美国总统特朗普23日称与伊朗已“基本谈成”一份包括开放霍尔木兹海峡在内的协议...
取用地下水的河南尉氏县,为何因... 极目新闻记者 詹钘连续呕吐腹痛两天后,河南尉氏县居民段梅(化名)终于缓了过来。5月22日早晨,她尝试...
一次补税超5亿,知名医院怎么了... 5月20日,爱尔眼科医院集团股份有限公司发布公告称,经自查,公司需补缴税款3.48亿元、滞纳金1.7...