Spring 的 DAO 模块提供了对 JDBC,Hibernate,Mybatis 等 DAO 层支持, 本节介绍 DAO 模块对 JDBC 的支持. DAO 模块依赖 ommons-dbcp.jar,commons-pool.jar.
一, JdbcDaoSupport 的使用
传统的 JDBC 时需要创建连接, 打开, 执行 sql, 关闭连接这一系列的步骤, Spring 框架对 JDBC 进行了封装, 我们只需使用封装好的 JdbcTemplate 执行 sql 语句. 既然是 JdbcDaoSupport 的使用, 为什么是使用 JdbcTemplate 呢? 因为 JdbcDaoSupport 提供了 JdbcTemplate 对象, 通过 JdbcTemplate 对象进行数据库操作. 可以转到定义, 查看 JdbcDaoSupport,JdbcTemplate 两个类的具体实现. 我们通过下面的例子来了解 JdbcDaoSupport 的使用, 这里还是使用 JDBC 章节的数据库 daodemodb 和表 t_user 信息.
第一步, 根据 t_user 表信息准备 Model 类 User. 定义了 id,name,age,money 属性, 并声明了两个构造函数.
- package com.demo.model;
- public class User {
- @Override
- public String toString() {
- return "Id:"+this.getId()+"Name:"+this.getName()+"Age:"+this.getAge()+"Money:"+this.getMoney();
- }
- private int Id;
- private String Name;
- private int Age;
- private double Money;
- public User()
- {
- }
- public User(String name, int age, double money) {
- Name = name;
- Age = age;
- Money = money;
- }
- public int getId() {
- return Id;
- }
- public void setId(int id) {
- Id = id;
- }
- public String getName() {
- return Name;
- }
- public void setName(String name) {
- Name = name;
- }
- public int getAge() {
- return Age;
- }
- public void setAge(int age) {
- Age = age;
- }
- public double getMoney() {
- return Money;
- }
- public void setMoney(double money) {
- Money = money;
- }
- }
- View Code
第二步, 定义接口类 IUserDAO, 在接口中声明了两个方法, QueryAllUser 方法属于查询操作, 查询所有 User,AddUser 属于更新操作, 新增 User.
- package com.demo.model;
- import java.util.*;
- public interface IUserDAO {
- public List<User>QueryAllUser();
- public Boolean AddUser(User user);
- public Boolean transfer(int fromUserId, int toUserId, float transferMoney);
- }
- View Code
第三步, 就是 JdbcDaoSupport 的使用了, 在下面的 SpringDAODemo 类中首先继承了 JdbcDaoSupport, 同时实现了 IUserDAO 接口中的方法. JdbcDaoSupport 提供了 JdbcTemplate 对象, SpringDAODemo 继承了 JdbcDaoSupport, 所以也就可以直接获取到 JdbcTemplate 对象, 然后执行该对象的方法进行数据库操作.
- package com.demo.model;
- import java.util.*;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.jdbc.core.support.JdbcDaoSupport;
- public class SpringDAODemo extends JdbcDaoSupport implements IUserDAO {
- public static void main(String[] args) {
- ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
- BeanFactory factory=context;
- IUserDAO userDao=(IUserDAO)factory.getBean("userDao");
- User user=new User("JdbcDaoSupportTest",26,333.33);
- userDao.AddUser(user);
- List<User> list=userDao.QueryAllUser();
- for(User u:list)
- {
- System.out.println(u.toString());
- }
- }
- public List<User> QueryAllUser() {
- String sql="select id,name,age,money from t_user order by id desc";
- List<Map<String,Object>> list=getJdbcTemplate().queryForList(sql);
- List<User> userList=new ArrayList<User>();
- for(Map<String,Object> row:list)
- {
- User user=new User();
- user.setId((Integer)row.get("id"));
- user.setName((String)row.get("name"));
- user.setAge((Integer)row.get("age"));
- user.setMoney(Double.parseDouble(row.get("money").toString()));
- userList.add(user);
- }
- return userList;
- }
- public Boolean AddUser(User user) {
- String sql="insert into t_user (name,age,money) values (?,?,?)";
- int row=getJdbcTemplate().update(sql, new Object[]{user.getName(),user.getAge(),user.getMoney()});
- if(row>0)
- {
- System.out.println("数据新增成功!");
- return true;
- }
- return false;
- }
- }
- View Code
第四步, 配置属性. 在上面的 main 方法中先通过上下文获取到 bean 对象, 然后执行新增操作和查询操作. 但是上面的代码并未看到数据库信息, 这里还需要在 ApplicationContext.xml 中配置数据库信息, 并为 JdbcDaoSupportDemo 设置数据源. 为什么会有 dataSource 属性呢, 因为 JdbcDaoSupport 中包含这个属性.
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- ">
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName">
- <value>com.MySQL.jdbc.Driver</value>
- </property>
- <property name="url">
- <value>jdbc:MySQL://127.0.0.1:3306/daodemodb</value>
- </property>
- <property name="username">
- <value>root</value>
- </property>
- <property name="password">
- <value>123456</value>
- </property>
- </bean>
- <bean id="userDao" class="com.demo.model.SpringDAODemo" depends-on="dataSource">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- </beans>
- View Code
第五步, pom.xml 中配置的依赖信息. 例子是 Spring 中 DAO 的实现, 而且是对 jdbc 的封装, 所以包含 Spring 相关依赖和 jdbc 的相关依赖.
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.demo</groupId>
- <artifactId>SpringDAO</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <spring.version>5.0.0.RELEASE</spring.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-core</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>commons-dbcp</groupId>
- <artifactId>commons-dbcp</artifactId>
- <version>1.4</version>
- </dependency>
- <dependency>
- <groupId>commons-pool</groupId>
- <artifactId>commons-pool</artifactId>
- <version>1.6</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/MySQL/MySQL-connector-java -->
- <dependency>
- <groupId>MySQL</groupId>
- <artifactId>MySQL-connector-java</artifactId>
- <version>5.1.6</version>
- </dependency>
- </dependencies>
- </project>
- View Code
运行 SpringDAODemo, 可以发现数据库和打印结果中增加了一条记录.
二. MappingSqlQuery 的使用
在 JdbcDaoSupport 的使用小节获取所有 User 的方法 QueryAllUser() 中, 使用 getJdbcTemplate().queryForList() 返回的是 List<Map<String,Object>> 类型, 需要遍历转换成 Java 对象, 那问题来了, 查询的不止这一个方法, 可能以后会有条件查询的方法, 那每次都要把从数据库返回的 List<Map<String,Object>> 类型的 List 转一遍, 当然也可以专门写一个转换的方法, 这样每次传 List<Map<String,Object>> 类型的参数, 然后返回 List<User > 类型的值. 其实还有一种方式, 就是使用 MappingSqlQuery.MappingSqlQuery 是一个抽象类, 需要实现它的方法 mapRow().
第一步, 实现 MappingSqlQuery 抽象类, 这里在 UserMappingSqlQuery 类中实现了 mapRow() 方法.
- package com.demo.model;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import org.springframework.jdbc.object.MappingSqlQuery;
- public class UserMappingSqlQuery extends MappingSqlQuery<User>{
- @Override
- protected User mapRow(ResultSet rs, int rowNum) throws SQLException {
- User user=new User();
- user.setId((Integer)rs.getInt("id"));
- user.setName((String)rs.getString("name"));
- user.setAge((Integer)rs.getInt("age"));
- user.setMoney((Double)rs.getDouble("money"));
- return user;
- }
- }
- View Code
第二步, UserMappingSqlQuery 类的使用. 这里重写 SpringDAODemo 类中的 QueryAllUser() 方法. UserMappingSqlQuery 需要传入 DataSource 和 sql, 并执行 compile() 编译. 这里通过 getDataSource() 获取的是 JdbcDaoSupport 的 DataSource 属性. 如果有参数, 可以使用 setParameters() 设置参数, 下面的代码为了演示设置参数, 增加了 where 1=1 的查询条件.
- public List<User> QueryAllUser() {
- String sql="select id,name,age,money from t_user where ?";
- UserMappingSqlQuery userQuery=new UserMappingSqlQuery();
- userQuery.setDataSource(getDataSource());
- userQuery.setSql(sql);
- userQuery.setParameters(new SqlParameter(java.sql.Types.VARCHAR));
- userQuery.compile();
- return userQuery.execute(new Object[]{new String("1=1")});
- }
- View Code
三. SqlUpdate 的使用
SqlUpdate 主要是用来更新, 可以设置参数. SqlUpdate 可以将某个功能模块化. 通过下面的例子来了解下 SqlUpdate 的使用.
- package com.demo.model;
- import javax.sql.DataSource;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.jdbc.core.SqlParameter;
- import org.springframework.jdbc.object.SqlUpdate;
- public class UserSqlUpdate extends SqlUpdate{
- public static void main(String[] args) {
- ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
- BeanFactory factory=context;
- UserSqlUpdate userSqlUpdate=(UserSqlUpdate)factory.getBean("userSqlUpdate");
- userSqlUpdate.updateUserMoney("小李",666.66);
- }
- public UserSqlUpdate(DataSource ds) {
- setDataSource(ds);
- setSql("update t_user set money=? where name=?");
- declareParameter(new SqlParameter(java.sql.Types.DOUBLE) );
- declareParameter(new SqlParameter(java.sql.Types.VARCHAR) );
- compile();
- }
- public Boolean updateUserMoney(String name,double money)
- {
- int row= update(new Object[]{new Double(money),new String(name)});
- if(row>0)
- {
- System.out.println("数据新增成功!");
- return true;
- }
- return false;
- }
- }
- View Code
在 ApplicationContext.xml 中配置 userSqlUpdate 对应的 bean 节点.
- <bean id="userSqlUpdate" class="com.demo.model.UserSqlUpdate">
- <constructor-arg ref="dataSource" index="0"></constructor-arg>
- </bean>
- View Code
在上面的 UserSqlUpdate 中继承了 SqlUpdate, 通过 setDataSource,setSql 分别设置 SqlUpdate 的数据源和要执行的 sql. 在 main 方法中将 name 为小李的 money 修改为 666.66, 执行 main 方法之后会打印出数据新增成功, 数据库中小李的 money 改成了 666.66.
四. SqlFunction 的使用
SqlFunction 返回单一行的查询结果, 默认返回 int, 也可以重载返回其他类型. 下面直接在 main 函数中使用.
- package com.demo.model;
- import org.apache.commons.dbcp.BasicDataSource;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.jdbc.object.SqlFunction;
- public class SqlFunctionDemo {
- public static void main(String[] args) {
- ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
- BeanFactory factory=context;
- BasicDataSource dataSource=(BasicDataSource)factory.getBean("dataSource");
- SqlFunction sf=new SqlFunction(dataSource,"select count(1) from t_user;");
- sf.compile();
- int count=sf.run();
- System.out.println("User Count:"+count);
- }
- }
- View Code
五, 事务管理
至于什么是事务在 JDBC 章节已经介绍, 这里就不再说. JDBC 中有事务管理, Spring 使用 DataSourceTransactionManager 作为 JDBC 的事务管理者, 同时把被管理的对象使用 TransactionProxyFactoryBean 配置. 从名字也能猜出这里使用的设计模式是代理设计模式. 这是一个事务代理 Bean, 能够使用 IoC,AOP 等注入事务管理代码. 在 JDBC 中介绍事务时用的转账操作, 这里为了更好理解, 还是使用转账操作.
第一步, 在 IUserDAO 接口中增加转账方法 transfer.
public Boolean transfer(int fromUserId, int toUserId, float transferMoney);
第二步, 在 SpringDAODemo 类中实现 transfer. 从 fromUserId 这个用户转账到 toUserId 这个用户, outInMoney 方法就是执行 sql 更新数据库用户的 money. 这里如果人为制造一个异常, 把 int i=1/0; 这行注释取消, 就会在后面执行转账时自动回滚, 转账不会成功.
- public Boolean transfer(int fromUserId, int toUserId, float transferMoney) {
- Boolean out= outInMoney(fromUserId,-transferMoney);
- int i=1/0; // 事务回滚
- Boolean in=outInMoney(toUserId,transferMoney);
- return out∈
- }
- private Boolean outInMoney(int toUserId,float money)
- {
- String sql="update t_user set money=money+? where id=?";
- int row=getJdbcTemplate().update(sql, new Object[]{money,toUserId});
- if(row>0)
- {
- return true;
- }
- return false;
- }
- View Code
第三步, 配置事务, 在 ApplicationContext.xml 中配置事务管理对象 DataSourceTransactionManager, 设置事务代理对象 TransactionProxyFactoryBean.
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 配置业务层代理 -->
- <bean id="userDaoProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <!-- 配置目标对象 -->
- <property name="target" ref="userDao"/>
- <!-- 注入事务管理器 -->
- <property name="transactionManager" ref="transactionManager"/>
- <!-- 注入事务的属性 -->
- <property name="transactionAttributes">
- <props>
- <prop key="transfer">PROPAGATION_REQUIRED</prop>
- </props>
- </property>
- </bean>
- View Code
第四步, 执行转账操作, 在 main 方法中执行 transfer 方法, 为用户 1,2 进行转账, 如果 transfer 方法中人为制造的异常注释的话是可以正常转账, 取消注释则转账失败, 打印事务回滚.
- public static void main(String[] args) {
- ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
- BeanFactory factory=context;
- IUserDAO userDao=(IUserDAO)factory.getBean("userDaoProxy");
- try
- {
- userDao.transfer(1, 2, 100);
- }
- catch(Exception e)
- {
- System.out.println("事务回滚");
- }
- }
- View Code
来源: https://www.cnblogs.com/5ishare/p/9744729.html