Spring对数据库的操作在jdbc上面做了更深层次的封装,而JdbcTemplate便是Spring提供的一个操作数据库的便捷工具。我们可以借助JdbcTemplate来执行所有数据库操作,例如插入,更新,删除和从数据库中检索数据,并且有效避免直接使用jdbc带来的繁琐编码。
JdbcTemplate主要提供以下五种类型的方法:
● execute:可以用于执行任何SQL语句,一般用于执行DDL语句
● update、batchUpdate:用于执行新增、修改、删除等语句
● query、queryForXXX:用于执行查询相关的语句
● call:用于执行数据库存储过程和函数相关的语句
JdbcTemplate的优点:
(1)配置基于模板设置 (2)完成了资源的创建和释放的工作 (3)完成了对JDBC的核心流程的工作,包括SQL语句的创建和执行,简化了对JDBC的操作 (4)仅需要传递DataSource就可以把它实例化 (5)JdbcTemplate只需要创建一次,减少了代码复用的烦恼 (6)JdbcTemplate是线程安全类
JdbcDaoSupport:
spring中提供了一个可以操作数据库的对象,对象封装了jdbc技术 ————JDBCTemplate JDBC模板对象。
而JdbcDaoSupport则对JdbcTemplate进行了封装,所以要操作JdbcTemplate,或只需要继承JdbcDaoSupport即可。
当然,在大部分情况下,我们都会直接使用更加强大的持久化框架来访问数据库,比如MyBatis、Hibernate或者Spring Data JPA,我们这里讲解JdbcTemplate的整合,只是告诉大家有这么一种操作数据库的方式。
传统的JDBC回顾
JDBC 我们一定不陌生,刚开始学习的时候,我们写过很多很多重复的模板代码:
该实现有两个明显的缺点就是(1)需要自己管理连接 (2)Jdbc操作重复代码封装与编写
- C3P0工具类
package com.sikiedu.jdbc; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0_DataSource { // 建立连接的驱动驱动名称 private static final String DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver"; // 连接数据库的url private static final String URL = "jdbc:mysql://localhost:3306/games_db?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT+8"; // 连接的数据库账号 private static final String USERNAME = "root"; // 数据库连接池-连接的数据库密码 private static final String PASSWORD = "123456"; // 数据库连接池-最大活动链接 private static final int MAX_TOTAL = 20; // 数据库连接池-初始化时链接的数量 private static final int INITIAL_SIZE = 5; private static ComboPooledDataSource c3p0 = new ComboPooledDataSource();; // 初始化链接参数 static { try { c3p0.setDriverClass(DRIVER_CLASS_NAME); c3p0.setJdbcUrl(URL); c3p0.setUser(USERNAME); c3p0.setPassword(PASSWORD); c3p0.setInitialPoolSize(INITIAL_SIZE); c3p0.setMaxPoolSize(MAX_TOTAL); } catch (PropertyVetoException e) { e.printStackTrace(); } } // 提供获得链接 public static Connection getConnection() throws SQLException { return c3p0.getConnection(); } public static void close(Connection conn, PreparedStatement ps1, PreparedStatement ps2) { closeStatement(ps2); closeStatement(ps1); closeConnection(conn); } public static void close(Connection conn, Statement statement) { closeStatement(statement); closeConnection(conn); } public static void close(Connection conn, Statement statement, ResultSet resultSet) { closeResultSet(resultSet); closeStatement(statement); closeConnection(conn); } // 关闭Connection public static void closeConnection(Connection conn) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } // 关闭Statement public static void closeStatement(Statement statement) { try { if (statement != null) statement.close(); } catch (SQLException e) { e.printStackTrace(); } } // 关闭ResultSet public static void closeResultSet(ResultSet resultSet) { try { if (resultSet != null) resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } }C3P0_DataSource.java
- 传统jdbc操作数据库
public User selectUserById(Integer id) { String sql = "SELECT id,username,userpassword,balance,grgisterdate FROM games_db.user WHERE id = ?"; User user = null; // 声明 JDBC 变量 Connection conn = null; PreparedStatement ps = null; ResultSet res = null; try { // 使用C3P0工具类获取连接 conn = C3P0_DataSource.getConnection(); // 预编译SQL ps = conn.prepareStatement(sql); // 设置参数 ps.setInt(1, id); // 执行SQL res = ps.executeQuery(); // 组装结果集返回 POJO if (res.next()) { user = new User(); user.setId(res.getInt(1)); user.setUsername(res.getString(2)); user.setUserpassword(res.getString(3)); user.setBalance(res.getLong(4)); user.setGrgisterdate(res.getDate(5)); } } catch (Exception e) { e.printStackTrace(); } finally { // 使用C3P0工具类关闭数据源 C3P0_DataSource.close(conn, ps, res); } return user; }
Spring Jdbc实现
● 项目准备:
- 导包 spring-jdbc.jar、spring-tx.jar
- 数据库配置文件
1 jdbc.driverClass=com.mysql.jdbc.Driver 2 jdbc.jdbcUrl=jdbc:mysql://localhost:3306/games_db?useUnicode=true&characterEncoding=UTF-8&useSSL=true 3 jdbc.user=root 4 jdbc.password=123456db.properties
- 创建一个POJO类
1 package com.sikiedu.bean; 2 3 import java.util.Date; 4 5 public class User { 6 7 private Integer id; 8 private String username; 9 private String userpassword; 10 private Long balance; 11 private Date grgisterdate; 12 13 public Integer getId() { 14 return id; 15 } 16 17 public void setId(Integer id) { 18 this.id = id; 19 } 20 21 public String getUsername() { 22 return username; 23 } 24 25 public void setUsername(String username) { 26 this.username = username; 27 } 28 29 public String getUserpassword() { 30 return userpassword; 31 } 32 33 public void setUserpassword(String userpassword) { 34 this.userpassword = userpassword; 35 } 36 37 public Long getBalance() { 38 return balance; 39 } 40 41 public void setBalance(Long balance) { 42 this.balance = balance; 43 } 44 45 public Date getGrgisterdate() { 46 return grgisterdate; 47 } 48 49 public void setGrgisterdate(Date grgisterdate) { 50 this.grgisterdate = grgisterdate; 51 } 52 53 @Override 54 public String toString() { 55 return "User [id=" id ", username=" username ", userpassword=" userpassword ", balance=" balance 56 ", grgisterdate=" grgisterdate "]"; 57 } 58 59 }User.java
- UserDao接口类
1 package com.sikiedu.dao; 2 3 import java.util.List; 4 5 import com.sikiedu.bean.User; 6 7 public interface UserDao { 8 9 // 增 10 void save(User u); 11 12 // 删 13 void deleteUserById(Integer id); 14 15 // 改 16 void updateUser(User u); 17 18 // 查 19 // 根据id查找用户 20 User selectUserById(Integer id); 21 22 // 查找所有用户 23 List<User> selecuAllUser(); 24 25 // 查找用户数量 26 Integer selectUserCount(); 27 }UserDao.java
下面我们开始使用spring-jdbc操作数据库
● 使用JdbcTemplate操作数据库
- 实现UserDao接口,使用JdbcTemplate对象操作
package com.sikiedu.dao; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import com.sikiedu.bean.User; public class UserDaoImpl implements UserDao { private JdbcTemplate jt; public void setJt(JdbcTemplate jt) { this.jt = jt; } // 根据id查询用户 @Override public User selectUserById(Integer id) { String sql = "SELECT * FROM user WHERE id = ?"; User user = jt.queryForObject(sql, new RowMapper<User>() { @Override public User mapRow(ResultSet res, int index) throws SQLException { User u = new User(); u.setId(res.getInt("id")); u.setUsername(res.getString("username")); u.setUserpassword(res.getString("userpassword")); u.setBalance(res.getLong("balance")); u.setGrgisterdate(res.getDate("grgisterdate")); return u; } }, id); return user; } // 添加用户 @Override public void save(User u) { String sql = "INSERT INTO user(username,userpassword,balance,grgisterdate) VALUES(?,?,?,?)"; jt.update(sql, u.getUsername(), u.getUserpassword(), u.getBalance(), u.getGrgisterdate()); } // 根据id删除用户 @Override public void deleteUserById(Integer id) { String sql = "DELETE FROM user WHERE id = ?"; jt.update(sql, id); } // 修改用户 @Override public void updateUser(User u) { String sql = "UPDATE user SET username = ?,userpassword = ?,balance = ?,grgisterdate = ? WHERE id = ?"; jt.update(sql, u.getUsername(), u.getUserpassword(), u.getBalance(), u.getGrgisterdate(), u.getId()); } // 查询所有用户 @Override public List<User> selecuAllUser() { String sql = "SELECT * FROM user"; List<User> list = jt.query(sql, new RowMapper<User>() { @Override public User mapRow(ResultSet res, int index) throws SQLException { User user = new User(); user.setId(res.getInt("id")); user.setUsername(res.getString("username")); user.setUserpassword(res.getString("userpassword")); user.setBalance(res.getLong("balance")); user.setGrgisterdate(res.getDate("grgisterdate")); return user; } }); return list; } // 查询用户数量 @Override public Integer selectUserCount() { String sql = "SELECT COUNT(*) FROM user"; return jt.queryForObject(sql, Integer.class); } }
- 配置xml - 依赖关系 dao > jdbcTemplate > dataSource
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 读取配置文件 --> <context:property-placeholder location="db.properties" /> <!-- dataSource --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- jdbcTemplate --> <bean name="jt" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <!-- dao --> <bean name="userDao" class="com.sikiedu.dao.UserDaoImpl"> <property name="jt" ref="jt"></property> </bean> </beans>
● 使用JdbcDaoSupport
- 实现UserDao,继承JdbcDaoSupport,使用getJdbcTemplate操作
package com.sikiedu.dao; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.support.JdbcDaoSupport; import com.sikiedu.bean.User; public class UserDaoImpl extends JdbcDaoSupport implements UserDao { // 根据id查询用户 @Override public User selectUserById(Integer id) { String sql = "SELECT * FROM user WHERE id = ?"; User user = getJdbcTemplate().queryForObject(sql, new RowMapper<User>() { @Override public User mapRow(ResultSet res, int index) throws SQLException { User u = new User(); u.setId(res.getInt("id")); u.setUsername(res.getString("username")); u.setUserpassword(res.getString("userpassword")); u.setBalance(res.getLong("balance")); u.setGrgisterdate(res.getDate("grgisterdate")); return u; } }, id); return user; } // 添加用户 @Override public void save(User u) { String sql = "INSERT INTO user(username,userpassword,balance,grgisterdate) VALUES(?,?,?,?)"; getJdbcTemplate().update(sql, u.getUsername(), u.getUserpassword(), u.getBalance(), u.getGrgisterdate()); } // 根据id删除用户 @Override public void deleteUserById(Integer id) { String sql = "DELETE FROM user WHERE id = ?"; getJdbcTemplate().update(sql, id); } // 修改用户 @Override public void updateUser(User u) { String sql = "UPDATE user SET username = ?,userpassword = ?,balance = ?,grgisterdate = ? WHERE id = ?"; getJdbcTemplate().update(sql, u.getUsername(), u.getUserpassword(), u.getBalance(), u.getGrgisterdate(), u.getId()); } // 查询所有用户 @Override public List<User> selecuAllUser() { String sql = "SELECT * FROM user"; List<User> list = getJdbcTemplate().query(sql, new RowMapper<User>() { @Override public User mapRow(ResultSet res, int index) throws SQLException { User user = new User(); user.setId(res.getInt("id")); user.setUsername(res.getString("username")); user.setUserpassword(res.getString("userpassword")); user.setBalance(res.getLong("balance")); user.setGrgisterdate(res.getDate("grgisterdate")); return user; } }); return list; } // 查询用户数量 @Override public Integer selectUserCount() { String sql = "SELECT COUNT(*) FROM user"; return getJdbcTemplate().queryForObject(sql, Integer.class); } }
- 配置xml - 依赖关系 userDao > dataSource
继承JdbcDaoSupport不需要配置JdbcTemplate,只需要将数据源注入到继承JdbcDaoSupport的类即可
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 读取配置文件 --> <context:property-placeholder location="db.properties" /> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean name="userDao" class="com.sikiedu.dao.UserDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
● 测试
package com.sikiedu.test; import java.util.Date; import java.util.List; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.sikiedu.bean.User; import com.sikiedu.dao.UserDao; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext2.xml") public class JdbcTest2 { @Resource(name = "userDao") private UserDao userDao; // 增 @Test public void save() { User user = new User(); user.setUsername("大大毛"); user.setUserpassword("dm123"); user.setBalance(2000L); user.setGrgisterdate(new Date(System.currentTimeMillis())); userDao.save(user); } // 删 @Test public void deleteUserById() { userDao.deleteUserById(105); } // 改 @Test public void updateUser() { User user = new User(); user.setId(104); user.setUsername("diao毛"); user.setUserpassword("dm312"); user.setBalance(1000L); user.setGrgisterdate(new Date(System.currentTimeMillis())); userDao.updateUser(user); } // 查 @Test public void selectUserById() { User user = userDao.selectUserById(2); System.out.println(user); } @Test public void selecuAllUser() { List<User> list = userDao.selecuAllUser(); for (User u : list) { System.out.println(u); } } @Test public void selectUserCount() { Integer count = userDao.selectUserCount(); System.out.println(count); } }Test
RowMapper的使用:在Jdbc的操作中,有很多情况下是要将ResultSet里的数据封装到一个持久化Bean里,再把持久化Bean封装到集合中。这样会造成大量的代码的重复,不利于代码重用。而RowMapper正好解决了这个问题。