Spring完整揭秘(七):使用Spring JDBC访问数据

文章目录

        • DAO模式
          • DAO模式示例
        • JDBC API
        • 基于 Spring JdbcTemplate的数据访问层实现
          • 将SQLException转译到DataAccessException
          • SpringBoot使用JdbcTemplate的配置
          • JdbcTemplate的常用方法
        • 完整案例

DAO模式

  • 为了统一和简化软件系统的数据访问操作,在常规的Java软件系统分层中,都会定义DAO数据访问层,使用该模式,既可以分离业务逻辑与数据访问,又可以屏蔽各种数据底层操作的差异。
    Spring完整揭秘(七):使用Spring JDBC访问数据_第1张图片
DAO模式示例
  • 使用DAO模式访问用户数据
/**
 * 用户数据访问层(DAO)接口
 *
 * @author zhuhuix
 * @date 2020-08-01
 */

public interface UserDAO {
    // 查找所有用户
    List<User> findAll();

    // 根据id查找用户
    User findById(Long id);

    // 新增用户
    Long addUser(User user);

    // 更新用户
    void updateUser(User user);

    // 删除用户
    void deleteById(Long id);

    // 自定义添加通过用户名称查找用户信息
    List<User> findByName(String name);
}
  • 依赖DAO接口的业务逻辑层
public class UserService {
    private UserDAO userDAO;
    
    // 返回所有的用户
    public List<User> listUsers() {
        return userDAO.findAll();
    }

    // 保存用户
    public User saveUser(User user) {
        // 保存数据
        if (user.getId() != null && user.getId() != 0) {
            userDAO.updateUser(user);
        } else {
            userDAO.addUser(user);
        }
        return user;
    }

    // 删除用户
    public void deleteUser(Long id) {
        userDAO.deleteById(id);
    }

    // 查找用户
    public User findUser(Long id) {
        return userDAO.findById(id);
    }

    // 根据名称查找用户
    public List<User> searchUser(String name) {
        return userDAO.findByName(name);
    }
}

JDBC API

  • 在Spring JdbcTemplate诞生之前,开发人员需要使用JDBC API实现数据访问层:
/**
 * 使用JDBC API实现用户数据访问层
 *
 * @author zhuhuix
 * @date 2020-08-10
 */
public class UserDAOImpl implements UserDAO {
    @Override
    public User findById(Long id) throws SQLException {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user_info", "root", "root");
            String sql = "select id,name,email from user where id=" + id;
            Statement st = conn.createStatement();
            ResultSet resultSet = st.executeQuery(sql);
            User user = new User();
            if (resultSet != null) {
                user.setId(resultSet.getArray("id"));
                user.setName(resultSet.getArray("name"));
                user.setEmail(resultSet.getArray("email"));
            }
        } catch (SQLException ex) {
            throw new SQLException(ex);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ex) {
                    throw new SQLException(ex);
                }
            }
        }

    }
...
}
  • 由于JDBC API主要是面向底层的数据库操作,所以存在比较大的缺点:
  1. 需要频繁的创建数据库连接;
  2. 涉及到的增删改查等功能需要在各个java文件中编写大量代码
  3. 对于底层事务、数据类型转换等都需要手动处理,效率低下

基于 Spring JdbcTemplate的数据访问层实现

  • 为了解决JDBC API的缺点,Spring框架构建Spring JdbcTemplate模板类,封装了所有基于JDBC API的数据访问代码,同时也将数据访问异常统一纳入Spring异常管理。
    Spring完整揭秘(七):使用Spring JDBC访问数据_第2张图片
/**
 * 使用JdbcTemplate模板类实现用户数据访问层
 *
 * @author zhuhuix
 * @date 2020-08-10
 */
@Repository
public class UserDAOImpl implements UserDAO {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public List<User> findAll() {
        return jdbcTemplate.query("select id,name,email from user;",
                new Object[]{}, new BeanPropertyRowMapper<>(User.class));
    }

    @Override
    public User findById(Long id) {
        return jdbcTemplate.queryForObject("select id,name,email from user where id=?;",
                new Object[]{id}, new BeanPropertyRowMapper<>(User.class));
    }

    @Override
    public Long addUser(User user) {
        return Integer.toUnsignedLong(jdbcTemplate.update("insert into  user(name,email) values(?,?);"
                , user.getName(), user.getEmail()));
    }

    @Override
    public void updateUser(User user) {
        jdbcTemplate.update("update user set name=?,email=? where id =?;"
                , user.getName(), user.getEmail(), user.getId());
    }

    @Override
    public void deleteById(Long id) {
        jdbcTemplate.update("delete from user where id=?", new Object[]{id});
    }

    @Override
    public List<User> findByName(String name) {
        return jdbcTemplate.query("select id,name,email from user where name=?;",
                new Object[]{name}, new BeanPropertyRowMapper<>(User.class));
    }
}

  • 从以上代码可以看出,使用Spring JdbcTemplate模板类,开发人员只需关心与数据访问逻辑相关的东西 ,对于JDBC API底层实现的相关细节不用过多地考虑。
将SQLException转译到DataAccessException
  • Spring JdbcTemplate对SQLException所提供的异常信息进行统一转译,将基于JDBC API的数据访问异常纳入Spring身的异常体系中,极大地简化了业务逻辑层对数据访问异常的处理。
    Spring完整揭秘(七):使用Spring JDBC访问数据_第3张图片
  • 转译抽象类源码
public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExceptionTranslator {
	/**
	 * Pre-checks the arguments, calls {@link #doTranslate}, and invokes the
	 * {@link #getFallbackTranslator() fallback translator} if necessary.
	 */
	@Override
	@Nullable
	public DataAccessException translate(String task, @Nullable String sql, SQLException ex) {
		Assert.notNull(ex, "Cannot translate a null SQLException");

		DataAccessException dae = doTranslate(task, sql, ex);
		if (dae != null) {
			// Specific exception match found.
			return dae;
		}

		// Looking for a fallback...
		SQLExceptionTranslator fallback = getFallbackTranslator();
		if (fallback != null) {
			return fallback.translate(task, sql, ex);
		}

		return null;
	}
	...
}
SpringBoot使用JdbcTemplate的配置
  • 在SpringBoot中使用JdbcTemplate需完成以下配置:
# application.yml
spring:
  datasource:
    # 数据库驱动
    driver-class-name: com.mysql.jdbc.Driver
    # 数据库地址
    url: jdbc:mysql://localhost:3306/user_info
    # 数据库用户名
    username: root
    # 数据库密码
    password: root
JdbcTemplate的常用方法
  1. 查询方法
query 查询并对结果集自行封装
queryForObject() 查询并返回一个对象
queryForList() 查询并返回多条记录
queryForMap() 查询并返回一条记录
  1. 操作方法
execute 执行sql语句,无返回值
update 执行sql语句,返回受影响的行数
batchUpdate 执行批量更新

完整案例

  • 可参考本人文章Spring全家桶的深入学习(三):实现数据持久化

你可能感兴趣的:(java,spring,java,spring)