赵走x博客
网站访问量:151416
首页
书籍
软件
工具
古诗词
搜索
登录
32、使用MyBatis注解实现数据库操作
31、MyBaties使用XML配置文件实现数据库操作
30、Spring Boot构建MyBatis应用程序
29、MyBatis简介
28、实战:实现JdbcTemplate多数据源
27、使用JdbcTemplate操作数据库
26、JdbcTemplate入门
25、实战:实现Web API版本控制
24、使用Swagger生成Web API文档
23、Thymeleaf页面布局
22、Thymeleaf内置对象、内嵌变量
21、Thymeleaf内联
20、Thymeleaf语法
19、Thymeleaf表达式
18、Thymeleaf入门
17、全局异常处理
16、实战:实现优雅的数据返回
15、跳转指定页面
14、Spring Boot静态资源
13、Spring Boot数据转换配置
12、跨域访问
11、Web配置
10、过滤器
9、拦截器
8、数据验证
7、参数传递
6、URL映射
5、@ResponseBody
4、@RequestMapping
3、@Controller和@RestController
2、Web项目结构
1、spring-boot-starter-web介绍
27、使用JdbcTemplate操作数据库
资源编号:551856
热度:123
27、使用JdbcTemplate操作数据库
成功在Spring Boot项目中集成JdbcTemplate后,如何使用JdbcTemplate数据库连接模板操作数据库呢? 接下来以示例演示JdbcTemplate实现学生信息的增、删、改、查等操作,让我们在实践中边学边用,更好地理解和吸收。 # 一、实现学生数据管理功能 ### 步骤01 创建实体类。 根据之前创建的Student表结构创建对应的实体类Student,具体代码如下: ``` public class Student { private Long id; private String name; private int sex; private int age; public Student(){ } public Student(String name, int sex, int age) { this.name = name; this.sex = sex; this.age = age; } // 省略get、set方法 } ``` 需要注意的是,实体类的数据类型要和数据库字段一一对应。 ### 步骤02 定义Repository接口。 首先,创建StudentRepository接口并定义常用的增、删、改、查接口方法,示例代码如下: ``` public interface StudentRepository { int save(Student student); int update(Student student); int delete(long id); Student findById(long id); } ``` 在上面的示例中,在StudentRepository中定义了save()、update()、delete()和findById()方法。 然后,创建StudentRepositoryImpl类,继承StudentRepository接口,实现接口中的增、删、改、查等方法,示例代码如下: ``` @Repository public class StudentRepositoryImpl implements StudentRepository { @Autowired private JdbcTemplate jdbcTemplate; } ``` 在上面的示例中,在StudentRepositoryImpl类上使用@Repository注解用于标注数据访问组件JdbcTemplate,同时在类中注入JdbcTemplate实例。 ### 步骤03 实现增、删、改、查功能。 接下来逐个实现对应的增、删、改、查方法。 ##### 1)新增: 在StudentRepositoryImpl类中实现StudentRepository接口中的save()方法。示例代码如下: ``` @Override public int save(Student student) { return jdbcTemplate.update("INSERT INTO Student(name, sex, age) values(?, ?, ?)", student.getName(),student.getSex(),student.getAge()); } ``` 在JdbcTemplate中,除了查询有几个API之外,新增、删除与修改操作统一都调用update()方法来完成,传入SQL即可。 Update()方法的返回值就是SQL执行受影响的行数。 ##### 2)删除: 通过用户id删除用户信息,在StudentRepositoryImpl类中实现StudentRepository接口的update( )方法。示例代码如下: ``` @Override public int delete(long id) { return jdbcTemplate.update("DELETE FROM Student where id = ? ",id); } ``` 看到这里读者可能会有疑问:怎么新增、删除、修改都调用update()方法,这与其他的框架不一样?严格来说,新增、删除、修改都属于数据写入,通过update()执行对应的SQL语句即可实现对数据库中数据的变更。 ##### 3)修改: 修改和新增类似,在StudentRepositoryImpl类中实现StudentRepository接口的update()方法。示例代码如下: ``` @Override public int update(Student student) { return jdbcTemplate.update("UPDATE Student SET name = ? , password = ? , age = ? WHERE id=?", student.getName(),student.getSex(),student.getAge(),student.getId()); } ``` ##### 4)查询: 根据用户id查询用户信息,同样在StudentRepositoryImpl类中实现StudentRepository接口的findById()方法。示例代码如下: ``` @Override public Student findById(long id) { return jdbcTemplate.queryForObject("SELECT * FROM Student WHERE id=?", new Object[] { id }, new BeanPropertyRowMapper
(Student.class)); } ``` 在上面的示例中,JdbcTemplate执行查询相关的语句调用query()方法及queryForXXX()方法,查询对象调用queryForObject方法。JdbcTemplate支持将查询结果转换为实体对象,使用new BeanPropertyRowMapper
(Student.class)对返回的数据进行封装,它通过名称匹配的方式自动将数据列映射到指定类的实体类中。 在执行查询操作时,需要有一个RowMapper将查询出来的列和实体类中的属性一一对应起来:如果列名和属性名是相同的,那么可以直接使用BeanPropertyRowMapper; 如果列名和属性名不同,就需要开发者自己实现RowMapper接口,将数据列与实体类属性字段映射。 ### 步骤04 验证测试。 接下来对封装好的StudentRepository进行测试,测试StudentRepository中的各个方法是否正确。创建StudentRepositoryTests类,将studentRepository注入测试类中。 ``` @SpringBootTest class StudentRepositoryImplTest { @Autowired private StudentRepository studentRepository; @Test void save() { Student student =new Student("weiz",1,30); studentRepository.save(student); } @Test void update() { Student student =new Student("weiz",1,18); student.setId(1L); studentRepository.update(student); } @Test void delete() { studentRepository.delete(1L); } @Test void findById() { Student student = studentRepository.findById(1L); System.out.println("student == " + student.toString()); } } ``` 接下来,依次执行上面的单元测试方法,验证学生信息的增删改查功能是否正常,结果如图7-2所示。  结果表明单元测试执行正常,说明StudentRepository中的方法执行成功,也可以查看数据库中的数据是否符合预期。 # 二、复杂查询 JdbcTemplate除了封装update和query等这些常用的方法外,还可以实现数据的增删改查操作。 实际上,JdbcTemplate还封装了execute()、queryForXXX()等许多非常实用的方法,比如需要返回List对象时可以调用queryForList()方法,创建数据库表结构时可以调用execute()方法生成数据库表。下面通过一些简单的示例来演示这些方法的调用。 ### 1. execute()方法 调用JdbcTemplate的execute()方法执行SQL语句,生成数据库表结构。 ``` jdbcTemplate.execute("CREATE TABLE Student (id integer, name varchar(100))"); ``` 上面这个示例就是通过调用execute()方法执行建表语句,生成数据库表结构。 ### 2. queryForXXX()方法 使用JdbcTemplate进行查询时,需要返回各种不同的数据类型,调用queryForXXX()等方法即可。比如需要返回int类型,调用queryForInt()方法: ``` int count = jdbcTemplate.queryForInt("SELECT COUNT(*) FROM Student "); ``` 除了queryForInt()方法之外,还有像queryForList()等很多数据类型的方法可以直接返回需要的数据类型,无须额外的类型转换。 ### 3. 数据对象转换 前面提到可以使用BeanPropertyRowMapper类自动将查询到的数据转换为数据对象信息。针对数据库字段和实体属性不一致的情况,JdbcTemplate还提供了自定义RowMapper对象进行属性映射。 首先,创建一个属性映射类StudentRowMapper: ``` public class StudentRowMapper implements RowMapper
{ @Override public Student mapRow(ResultSet rs, int rowNum) throws SQLException { Student student = new Student(); student.setId(rs.getLong("id")); student.setName(rs.getString("name")); student.setSex(rs.getInt("sex")); student.setAge(rs.getInt("age")); return student; } } ``` 在上面的示例中,自定义的StudentRowMapper类继承JdbcTemplate中的RowMapper类。重写mapRow()方法,将结果集中的数据转换为Student对象。 然后,创建单元测试,验证数据对象转换,示例代码如下: ``` @Test void rowMapper() { List
students = jdbcTemplate.query("SELECT * FROM student", new StudentRowMapper()); for(Student student : students){ System.out.println("id:"+student.getId()+",name:"+student.getName()); } } ``` 在上面的示例中,调用query()返回Student列表数据,传入StudentRowMapper参数,将查询结果转换为用户列表并返回。 ### 4. 返回主键 前面介绍了数据的新增,但是有些时候需要在数据插入的过程中返回主键,那么可以调用PreparedStatementCreator(),代码如下: ``` @Test public void save2() { Student student = new Student("zhangsan",1,20); KeyHolder keyHolder = new GeneratedKeyHolder(); int id = jdbcTemplate.update(new PreparedStatementCreator() { @Override public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { PreparedStatement ps = connection.prepareStatement("insert into student (name,sex,age) values (?,?,?);", Statement.RETURN_GENERATED_KEYS); ps.setString(1, student.getName()); ps.setInt(2, student.getSex()); ps.setInt(3, student.getAge()); return ps; } }, keyHolder); student.setId(keyHolder.getKey().longValue()); System.out.println(keyHolder.getKey().longValue()); } ``` 在上面的示例中,实际上就相当于调用了JDBC中的方法,首先在构建PreparedStatement时传入Statement.RETURN_GENERATED_KEYS,然后传入KeyHolder,最终从KeyHolder中获取刚刚插入数据的id,保存到student对象的id属性中。 单击Run Test或在方法上右击,选择Run 'save2',运行测试方法,结果如图7-3所示。  结果结果表明单元测试方法save2运行成功,并输出了相应的结果。这说明数据已经插入成功并返回了数据的主键id。 ### 5. 存储过程 由于各种ORM框架的流行,存储过程的使用场景已经不多见了。但是,JdbcTemplate对存储过程同样进行了良好的封装。下面通过一个示例来演示JdbcTemplate是如何调用存储过程的。 ``` public void test() { List resultList = (List) jdbcTemplate.execute( new CallableStatementCreator() { public CallableStatement createCallableStatement(Connection con) throws SQLException { String storedProc = "{call testpro(?,?)}";// 调用的sql CallableStatement cs = con.prepareCall(storedProc); cs.setString(1, "p1");// 设置输入参数的值 cs.registerOutParameter(2, OracleTypes.CURSOR);// 注册输出参数的类型 return cs; } }, new CallableStatementCallback() { public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException { List resultsMap = new ArrayList(); cs.execute(); ResultSet rs = (ResultSet) cs.getObject(2);// 获取游标一行的值 while (rs.next()) {// 转换每行的返回值到Map中 Map rowMap = new HashMap(); rowMap.put("id", rs.getString("id")); rowMap.put("name", rs.getString("name")); resultsMap.add(rowMap); } rs.close(); return resultsMap; } }); for (int i = 0; i < resultList.size(); i++) { Map rowMap = (Map) resultList.get(i); String id = rowMap.get("id").toString(); String name = rowMap.get("name").toString(); System.out.println("id=" + id + ";name=" + name); } } ``` 示例代码说明: - 1)JdbcTemplete通过execute()方法执行存储过程并获得输出结果。 - 2)通过CallableStatement类的prepareCall()方法设置调用的存储过程名称和输入、输出参数。 - 3)通过CallableStatementCallback中的doInCallableStatement()方法执行对应的存储过程,并返回执行结果。