Beginning Spring学习笔记——第4章(二)使用Spring执行数据访问操作
来源:互联网 发布:java api文档在哪里 编辑:程序博客网 时间:2024/06/02 06:07
使用JdbcTemplate运行查询
常用query(), queryForObject(), queryForList(), queryForMap(), queryForRowSet()以及它们的重载版本进行查询
下queryForObject()实现AccountDaoJdbcImpl中的find(long accountId)方法
public Account find(long accountId) { return jdbcTemplate .queryForObject( "select id,owner_name,balance,access_time,locked from account where id = ?", new RowMapper<Account>() { public Account mapRow(ResultSet rs, int rowNum) throws SQLException { Account account = new Account(); account.setId(rs.getLong("id")); account.setOwnerName(rs.getString("owner_name")); account.setBalance(rs.getDouble("balance")); account.setAccessTime(rs .getTimestamp("access_time")); account.setLocked(rs.getBoolean("locked")); return account; } }, accountId); }
然后使用如下SQL语句插入一个账户
INSERT INTO ACCOUNT (ID, OWNER_NAME, BALANCE, ACCESS_TIME, LOCKED) VALUES (100, 'Van Gogh', 10.0 , '2017-08-29', false)
再在Main函数中使用accountDao Bean获取账户记录
public class Main { public static void main(String[] args) throws SQLException { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Ch4Configuration.class); AccountDao accountDao = applicationContext.getBean(AccountDao.class); Account account = accountDao.find(100L); System.out.println(account.getId()); System.out.println(account.getOwnerName()); System.out.println(account.getBalance()); System.out.println(account.getAccessTime()); System.out.println(account.isLocked()); }}
得到结果
相比直接使用JDBC,这种方法在模板类的回调方法中封装了所有需要的数据访问逻辑。
在查询中我们还可以使用命名参数,首先在数据访问实现类中定义命名参数,再用它实现find方法返回有相同用户名的所有账户。
public class AccountDaoJdbcImpl implements AccountDao { private JdbcTemplate jdbcTemplate; private NamedParameterJdbcTemplate namedParameterJdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate); } public List<Account> find(String ownerName) { return namedParameterJdbcTemplate.query( "select id,owner_name,balance,access_time,locked from account where owner_name = :ownerName" , Collections.singletonMap("ownerName", ownerName), new RowMapper<Account>() { public Account mapRow(ResultSet rs, int rowNum) throws SQLException { Account account = new Account(); account.setId(rs.getLong("id")); account.setOwnerName(rs.getString("owner_name")); account.setBalance(rs.getDouble("balance")); account.setAccessTime(rs.getTimestamp("access_time")); account.setLocked(rs.getBoolean("locked")); return account; } }); }
还可以使用PreparedStatement,使得多次执行相同查询的预处理步骤只执行一次从而节省时间。
public List<Account> find(final boolean locked) { PreparedStatementCreatorFactory psCreatorFactory = new PreparedStatementCreatorFactory( "select * from account where locked = ?", new int[] { Types.BOOLEAN }); return jdbcTemplate.query(psCreatorFactory .newPreparedStatementCreator(new Object[] { locked }), new RowMapper<Account>() { public Account mapRow(ResultSet rs, int rowNum) throws SQLException { Account account = new Account(); account.setId(rs.getLong("id")); account.setOwnerName(rs.getString("owner_name")); account.setBalance(rs.getDouble("balance")); account.setAccessTime(rs.getTimestamp("access_time")); account.setLocked(rs.getBoolean("locked")); return account; } }); }
以上代码为获取某种锁定状态的所有账户的查找。
使用JdbcTemplate插入、更新和删除记录
通过JdbcTemplate的update()及其重载方法实现。
首先创建三个异常类表示插入、更新和删除失败,在三个函数失败时创建。
public class InsertFailedException extends DataAccessException { public InsertFailedException(String msg) { super(msg); }}public class UpdateFailedException extends DataAccessException { public UpdateFailedException(String msg) { super(msg); }}public class DeleteFailedException extends DataAccessException { public DeleteFailedException(String msg) { super(msg); }}
然后创建插入函数
public void insert(Account account) { PreparedStatementCreatorFactory psCreatorFactory = new PreparedStatementCreatorFactory( "insert into account(owner_name,balance,access_time,locked) values(?,?,?,?)", new int[] { Types.VARCHAR, Types.DOUBLE, Types.TIMESTAMP, Types.BOOLEAN }); KeyHolder keyHolder = new GeneratedKeyHolder(); int count = jdbcTemplate.update( psCreatorFactory.newPreparedStatementCreator(new Object[] { account.getOwnerName(), account.getBalance(), account.getAccessTime(), account.isLocked() }), keyHolder); if (count != 1) throw new InsertFailedException("Cannot insert account"); account.setId(keyHolder.getKey().longValue()); }
值得注意的是为了防止主键ID的重复,此处的ID为KeyHolder自动生成。插入操作由PreparedStatement完成。
然后创建更新函数:
public void update(Account account) { int count = jdbcTemplate .update("update account set (owner_name,balance,access_time,locked) = (?,?,?,?) where id = ?", account.getOwnerName(), account.getBalance(), account.getAccessTime(), account.isLocked(), account.getId()); if (count != 1) throw new UpdateFailedException("Cannot update account"); }
此处直接用JdbcTemplate完成。
最后创建删除函数:
public void delete(long accountId) { int count = jdbcTemplate.update("delete account where id = ?", accountId); if (count != 1) throw new DeleteFailedException("Cannot delete account"); }
使用SimpleJdbcCall调用和储存过程
在Main函数中创建SimpleJdbcCall实例,指定要执行的储存过程名并声明输入输出参数,若返回ResultSet则分配名称并用RowMapper处理。然后用compile()编译过程,用execute执行。
public class Main { public static void main(String[] args) throws SQLException { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Ch4Configuration.class); JdbcTemplate jdbcTemplate = applicationContext.getBean(JdbcTemplate.class); SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate); simpleJdbcCall .withProcedureName("concat") .withoutProcedureColumnMetaDataAccess() .declareParameters( new SqlParameter("param1", Types.VARCHAR), new SqlParameter("param2", Types.VARCHAR)). returningResultSet("result", new SingleColumnRowMapper<String>(String.class)); simpleJdbcCall.compile(); Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("param1", "hello "); paramMap.put("param2", "world!"); Map<String,Object> resultMap = simpleJdbcCall.execute(paramMap); List<String> resultList = (List<String>) resultMap.get("result"); for(String value:resultList) { System.out.println(value); } }}
运行得到结果,拼接了两个String实例。
用batchUpdate执行批处理操作
在一个PreparedStatement中执行一系列更新操作以减少往返数据库次数,提高性能
public void update(final List<Account> accounts) { int[] counts = jdbcTemplate.batchUpdate( "update account set (owner_name,balance,access_time,locked) = (?,?,?,?) where id = ?", new BatchPreparedStatementSetter() { public void setValues(PreparedStatement ps, int i) throws SQLException { Account account = accounts.get(i); ps.setString(1, account.getOwnerName()); ps.setDouble(2, account.getBalance()); ps.setTimestamp(3, new Timestamp(account.getAccessTime().getTime())); ps.setBoolean(4, account.isLocked()); ps.setLong(5, account.getId()); } public int getBatchSize() { return accounts.size(); } }); int i = 0; for(int count:counts) { if(count == 0) throw new UpdateFailedException("Row not updated :" + i); i++; } }
以上代码对列表accounts内的所有用户进行了更新。
处理LOB对象
分CLOB(Character Large Object)和BLOB(Binary Large Object)两种,用于处理二进制大型数据和文本大型数据。都使用LobHandler和LobCreator接口处理,分别用来访问和设置LOB值。
final LobHandler lobHandler = new DefaultLobHandler(); final String textualContent = "test"; final byte[] binaryContent = textualContent.getBytes(); final long accountId = 100L; jdbcTemplate .update("update account set (owner_photo,account_desc) = (?,?) where id = ? ", new PreparedStatementSetter() { public void setValues(PreparedStatement ps) throws SQLException { LobCreator lobCreator = lobHandler .getLobCreator(); lobCreator.setBlobAsBytes(ps, 1, binaryContent); lobCreator.setClobAsString(ps, 2, textualContent); ps.setLong(3, accountId); } });
- Beginning Spring学习笔记——第4章(二)使用Spring执行数据访问操作
- Beginning Spring学习笔记——第6章(二)使用Spring进行声明式事务管理
- Beginning Spring学习笔记——第5章(二)Spring的JPA支持
- Beginning Spring学习笔记——第2章(二)依赖注入
- Beginning Spring学习笔记——第3章(二)表单处理
- Beginning Spring学习笔记——第4章(一)Spring JDBC连接的配置
- Beginning Spring学习笔记——第4章(三)将JDBC操作模块化为Java对象
- Beginning Spring学习笔记——第7章 使用Spring进行测试驱动开发
- Beginning Spring学习笔记——第6章(三)使用Spring进行编程式事务管理
- Beginning Spring学习笔记——第1章
- Beginning Spring学习笔记——第9章 SpEL
- Beginning Spring学习笔记——第10章 缓存
- Beginning Spring学习笔记——第2章(一)Spring IoC容器
- Beginning Spring学习笔记——第2章(三)Spring的Bean管理
- Beginning Spring学习笔记——第3章(一)Spring MVC基础
- Beginning Spring学习笔记——第6章(一)Spring事务管理基础
- Beginning Spring学习笔记——第11章 使用Spring开发REST风格的Web服务
- Beginning Spring学习笔记——第5章(一)ORM和JPA基础
- Mysql动态操作表或者列
- PHP post数据传输部分缺失
- Beginning Spring学习笔记——第4章(一)Spring JDBC连接的配置
- 为什么会觉得无聊?
- Leetcode 56. Merge Intervals
- Beginning Spring学习笔记——第4章(二)使用Spring执行数据访问操作
- Hexo的安装记录
- android动画的学习体会
- 浅谈Web渗透测试中的信息收集
- C#
- mybatis Invalid bound statement (not found)
- Confluent Platform部署
- 数位分离以及转化成k进制--Integer to Roman
- 【译】如何应对 CNN 中的过拟合问题