【1】JdbcTemplate
为了使 JDBC 更加易于使用, Spring 在 JDBC API 上定义了一个抽象层, 以此建立一个 JDBC 存取框架。
作为 Spring JDBC 框架的核心, JDBC 模板的设计目的是为不同类型的 JDBC 操作提供模板方法. 每个模板方法都能控制整个过程, 并允许覆盖过程中的特定任务. 通过这种方式, 可以在尽可能保留灵活性的情况下, 将数据库存取的工作量降到最低.
① XML配置
<!-- ********配置Spring的JdbcTemplate********* --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>
②使用实例
① Update
String sql = "update customers set name=?,address=? where id=? "; jdbcTemplate.update(sql, "Tom","北京",64);
② BatchUpdate
String sql = "insert into customers(name,address,phone) values(?,?,?) "; List<Object[]> batchArgs = new ArrayList<Object[]>(); batchArgs.add(new Object[]{"tom1","北京","1392356824"}); batchArgs.add(new Object[]{"tom2","南京","1392356824"}); batchArgs.add(new Object[]{"tom3","东京","1392356824"}); batchArgs.add(new Object[]{"tom4","西京","1392356824"}); batchArgs.add(new Object[]{"tom5","边梁","1392356824"}); jdbcTemplate.batchUpdate(sql, batchArgs);
③ QueryForObject
/**/** * 获取单个列的值, 或做统计查询 * 使用 queryForObject(String sql, Class<Long> requiredType) */ @Test public void testQueryObject2(){ String sql = "select name from test_user where id = ? "; String name = jdbcTemplate.queryForObject(sql, String.class,1); System.out.println(name); }
④ queryForObject返回一个对象
从数据库中获取一条记录, 实际得到对应的一个对象,注意不是调用 queryForObject(String sql, Class<Employee> requiredType, Object... args) 方法!
而需要调用 queryForObject(String sql, RowMapper<Employee> rowMapper, Object... args)
其中的 RowMapper 指定如何去映射结果集的行, 常用的实现类为 BeanPropertyRowMapper
使用 SQL 中列的别名完成列名和类的属性名的映射. 例如 last_name lastName
不支持级联属性. JdbcTemplate 到底是一个 JDBC 的小工具, 而不是 ORM 框架
@Test public void testQueryForObject(){ String sql = "select id,name,password,balance ,dept_id as \"department.id\" from test_user where id=? "; RowMapper<User> rowMapper = new BeanPropertyRowMapper<User>(User.class); User user = jdbcTemplate.queryForObject(sql, rowMapper,1); System.out.println(user); }
⑤ Query返回实体类集合
/** * 查到实体类的集合 * 注意调用的不是 queryForList 方法 */ @Test public void testQueryForList(){ String sql = "select id,name,password,balance from test_user where id >= ? "; RowMapper<User> rowMapper = new BeanPropertyRowMapper<User>(User.class); List<User> users = jdbcTemplate.query(sql, rowMapper, 1); System.out.println(users); } //如下返回对象集合 List<TZhuanjia> queryList =jdbcTemplate.query(sql, new RowMapper() { public TZhuanjia mapRow(ResultSet rs, int rowNum) throws SQLException { TZhuanjia tZhuanjia = new TZhuanjia(); int id = rs.getInt("id"); tZhuanjia.setId(id); int yiyuanId = rs.getInt("yiyuanId"); tZhuanjia.setId(yiyuanId); int keshiId = rs.getInt("keshiId"); tZhuanjia.setId(keshiId); int nianling = rs.getInt("nianling"); tZhuanjia.setNianling(nianling); String xingming = rs.getString("xingming"); tZhuanjia.setXingming(xingming); String xingbie = rs.getString("xingbie"); tZhuanjia.setXingbie(xingbie); String shanchang = rs.getString("shanchang"); tZhuanjia.setShanchang(shanchang); String leixing = rs.getString("leixing"); tZhuanjia.setLeixing(leixing); String fujian = rs.getString("fujian"); tZhuanjia.setFujian(fujian); String del = rs.getString("del"); tZhuanjia.setDel(del); return tZhuanjia; }; });
PS:JdbcTemplate不支持级联属性,故如下将不会得到department对象:
String sql = "select id,name,password,balance ,dept_id as \"department.id\" from test_user where id=? ";
③ DAO中注入JdbcTemplate
每次使用都创建一个 JdbcTemplate 的新实例, 这种做法效率很低下。
JdbcTemplate 类被设计成为线程安全的, 所以可以在 IOC 容器中声明它的单个实例, 并将这个实例注入到所有的 DAO 实例中。
XML配置:
<bean id="userDAO" class="com.web.jdbc.UserDAO"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean>
【2】JdbcDaoSupport
每次使用都创建一个 JdbcTemplate 的新实例, 这种做法效率很低下。JdbcTemplate 类被设计成为线程安全的, 所以可以再 IOC 容器中声明它的单个实例, 并将这个实例注入到所有的 DAO 实例中。
JdbcTemplate 也利用了 Java 1.5 的特定(自动装箱, 泛型, 可变长度等)来简化开发。
Spring JDBC 框架还提供了一个 JdbcDaoSupport 类来简化 DAO 实现。该类声明了 jdbcTemplate 属性, 它可以从 IOC 容器中注入, 或者自动从数据源中创建。
其类继承树示意图
也就是说其维护了JdbcTemplate,对应的其子类NamedParameterJdbcDaoSupport维护了NamedParameterJdbcTemplate。
@Repository public class DepartmentDAO extends JdbcDaoSupport { @Autowired public void setDataSource2(DataSource dataSource){ setDataSource(dataSource); } public Department getDepartment(int id){ String sql="select department_id id,department_name deptName from department where department_id=?"; RowMapper rowMapper = new BeanPropertyRowMapper<Department>(Department.class); Department department = getJdbcTemplate().queryForObject(sql, rowMapper, id); return department; } }
【3】NamedParameterJdbcTemplate
在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制。
定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定.
在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter)。
具名参数:
SQL 按名称(以冒号开头)而不是按位置进行指定.
具名参数更易于维护, 也提升了可读性. 具名参数由框架类在运行时用占位符取代
具名参数只在 NamedParameterJdbcTemplate 中得到支持
在 SQL 语句中使用具名参数时, 可以在一个 Map 中提供参数值, 参数名为键
也可以使用 SqlParameterSource 参数。批量更新时可以提供 Map 或 SqlParameterSource 的数组。
① update(sql, paramMap)
/** * 可以为参数起名字. * 1. 好处: 若有多个参数, 则不用再去对应位置, 直接对应参数名, 便于维护 * 2. 缺点: 较为麻烦. */ @Test public void testNamedParameterJdbcTemplate(){ String sql="insert into test_user(id,name,password,balance) values(:id,:name,:password,:balance)"; Map<String, Object> map = new HashMap<String, Object>(); /*此处不再添加 " :"*/ map.put("id", 3); map.put("name", "兰芝"); map.put("password", 123456); map.put("balance", 500); namedParameterJdbcTemplate.update(sql, map); }
② update(sql, parameterSource)
使用具名参数时, 可以使用 update(String sql, SqlParameterSource paramSource)
方法进行更新操作。SQL 语句中的参数名和类的属性一致。
使用 SqlParameterSource 的 BeanPropertySqlParameterSource
实现类作为参数.
@Test public void testNamedParameterJdbcTemplate2(){ String sql="insert into test_user(name,password,balance) values(:name,:password,:balance)"; User user = new User(); user.setName("行之"); user.setPassword("1241"); user.setBalance("235"); SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(user); namedParameterJdbcTemplate.update(sql, parameterSource); }