Spring实战学习笔记 —— 2.使用数据

本文详细介绍了在Spring应用中如何使用JDBC和JPA进行数据操作。首先,通过Spring Data JDBC展示了如何读取和写入数据,提到了SimpleJdbcInsert的使用。接着,深入讲解了JPA持久化数据,包括实体类的处理,如@Entity、@Table、@Id等注解的用法,以及JPA Repository的声明和扩展。
摘要由CSDN通过智能技术生成

1. 使用JDBC读取和写入数据

Spring同时支持JDBC和JPA两种抽象形式,Spring对于JDBC的支持要归功于JdbcTemplate类(Spring Data JDBC)。

如果在应用的根类路径下存在名为schema.sql和data.sql的文件,那么在应用启动的时候将会基于数据库执行文件中的SQL。

1.1 Spring Data JDBC

Spring Data JDBC是将传统数据库查询进行封装,以queryForObject为例。

@Autowired
JdbcTemplate jdbc;

public Order findOne(String id) {
	return jdbc.queryForObject("select * from order where id = ?", this::mapRowToOrder, id);
}

private Order mapRowToOrder(ResultSet rs, int rowNum) {
	return new Order(rs.getString("id"), rs.getString("code")....);
}
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
	// 方法入口,RowMapper实体类处理器
	@Nullable
    public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        List<T> results = this.query(sql, rowMapper);
        return DataAccessUtils.nullableSingleResult(results);
    }

	// 返回校验
    @Nullable
    public static <T> T nullableSingleResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
        if (CollectionUtils.isEmpty(results)) {
            throw new EmptyResultDataAccessException(1);
        } else if (results.size() > 1) {
            throw new IncorrectResultSizeDataAccessException(1, results.size());
        } else {
            return results.iterator().next();
        }
    }
	
	// 查询入口,RowMapperResultSetExtractor行数据提取器,用于提取多行数据
	public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        return (List)result(this.query((String)sql, (ResultSetExtractor)(new RowMapperResultSetExtractor(rowMapper))));
    }

	// 通过构造回调类,使查询后进入行数据提取器从而根据不同的类构造不同的实体类
    @Nullable
    public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
        Assert.notNull(sql, "SQL must not be null");
        Assert.notNull(rse, "ResultSetExtractor must not be null");
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Executing SQL query [" + sql + "]");
        }

        class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
            QueryStatementCallback() {
            }

            @Nullable
            public T doInStatement(Statement stmt) throws SQLException {
                ResultSet rs = null;

                Object var3;
                try {
                    rs = stmt.executeQuery(sql);
                    var3 = rse.extractData(rs);
                } finally {
                    JdbcUtils.closeResultSet(rs);
                }

                return var3;
            }

            public String getSql() {
                return sql;
            }
        }

        return this.execute((StatementCallback)(new QueryStatementCallback()));
    }
	
	// jdbc开启查询,也是传统jdbc代码
    @Nullable
    public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");
        Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
        Statement stmt = null;

        Object var11;
        try {
            stmt = con.createStatement();
            this.applyStatementSettings(stmt);
            T result = action.doInStatement(stmt);
            this.handleWarnings(stmt);
            var11 = result;
        } catch (SQLException var9) {
            String sql = getSql(action);
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            DataSourceUtils.releaseConnection(con, this.getDataSource());
            con = null;
            throw this.translateException("StatementCallback", sql, var9);
        } finally {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }

        return var11;
    }
}

对于增删改,可以使用

// 自增主键
PreparedStatementCreaetor psc = new PreparedStatementCreatorFactory("insert into order(code) valus (?)",
									Types.BIGINT, Types.VARCHAR)
									.newPreparedStatementCreator(Arrays.asList(order.getCode()));
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbc.update(psc, key Holder);
return keyHolder.getKey().longValue();

或

jdbc.update("insert into order(id, code) valus (?, ?)", order.getId(), order.getCode());

1.2 SimpleJdbcInsert

@Repository
public class JdbcOrderRepository {
	private SimpleJdbcInsert orderInsertGenerated;
	private SimpleJdbcInsert orderInsert;
	private ObjectMapper objectMapper;
	
	@Autowired
	public JdbcOrderRepository(JdbcTemplate jdbc) {
		this.orderInsertGenerated = new SimpleJdbcInsert(jdbc).withTableName("order").usingGeneratedKeyColumns("id");
		this.orderInsert = new SimpleJdbcInsert(jdbc).withTableName("order");
		this.objectMapper = new ObjectMapper;
	}
	
	public Long save(Order order) {
		long id = orderInsertGenerated.executeAndReturnKey(objectMapper.convertValue(order, Map.class)).longValue();
		return id;
	}

	public void save(Order order, long id) {
		Map<String, Object> values = new HashMap<String, Object>();
		values.put("id", id);
		values.put("code", code);
		orderInsert.execute(values);
	}
}

2.使用JPA持久化数据

2.1 实体类处理

@Entity
声明在类名上,表示为JPA实体

@Table(name=“table name”)
声明在类名上,表示对应的数据表名称

@Id
声明在属性上,表示为数据库主键

@GeneratedValue(strategy=GenerationType.AUTO)
声明在属性上,表示为自增属性

@ManyToMany
声明在其他实体类对象或集合上,表示与其他实体类的对应关系为多对多

@PrePersist
声明在方法上,表示在持久化到数据库前需要执行的方法

2.2 声明JPA Repository

public interface OrderRepository extends CrudRepository<Order, Long> {

}

通过继承CrudRepository,并指定实体类与主键类型,不需要实现具体方法即可使用CrudRepository中自带的方法,运行器JPA会自动生成实现类。

同时,可以通过Spring Data方法签名来让JPA生成更多的我们需要的方法,如:

List<Order> readOrdersByCodeAndIdBetweenOrderById(String code, long startId, long endId);
查找Order表是因为我们在CrudRepository中声明了实体类,实体类中声明了对应表
read:读取数据,可用get或find替换
By:开始声明要匹配的属性
Code:匹配属性
And:同SQL中的and
Id:匹配属性
Between:值必须在给定的范围内
OrderBy: 排序

还有更多的方法签名可以自行查阅

或者

@Query("from order where code = ‘123’")
List<Order> readOrdersByCode()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值