Использование JDBC
Хотя в Jmix для доступа к данным в основном используется JPA, существуют некоторые сценарии, в которых может потребоваться прямой доступ через JDBC, например, выполнение сложных SQL-запросов, пакетных операций или вызов хранимых процедур.
Мы рекомендуем использовать DataManager и прибегать к JDBC только при необходимости. |
Для выполнения запросов на уровне JDBC можно использовать классы JdbcTemplate
или JdbcClient
, предоставляемые Spring.
И JdbcTemplate
, и JdbcClient
автоматически участвуют в управляемых Spring транзакциях, поэтому вы можете использовать их вместе с операциями JPA в рамках одной транзакции.
Использование JdbcTemplate
JdbcTemplate
— это классический класс Spring Framework, который упрощает операции с JDBC, обеспечивая управление ресурсами и преобразование исключений.
Чтобы использовать JdbcTemplate
для доступа к основному хранилищу данных, просто инжектируйте его в ваш бин:
@Autowired
private JdbcTemplate jdbcTemplate;
public Map<String, BigDecimal> getCustomerAmounts(CustomerGrade grade) {
return jdbcTemplate.query(
"""
select c.NAME, sum(o.AMOUNT)
from CUSTOMER c join ORDER_ o on c.ID = o.CUSTOMER_ID
where c.GRADE = ?
group by c.NAME
""",
(ResultSet rs) -> {
Map<String, BigDecimal> result = new HashMap<>();
while (rs.next()) {
result.put(rs.getString(1), rs.getBigDecimal(2));
}
return result;
},
grade.getId()
);
}
Если вам нужен доступ к дополнительному хранилищу данных, инжектируйте соответствующий javax.sql.DataSource
и создайте новый экземпляр JdbcTemplate
. В следующем примере JdbcTemplate
создается для хранилища данных db1
:
@Autowired
@Qualifier("db1DataSource")
private DataSource db1DataSource;
public List<String> loadFooNames() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(db1DataSource);
return jdbcTemplate.queryForList("select NAME from SAMPLE_FOO", String.class);
}
Использование JdbcClient
JdbcClient
, представленный в Spring Framework 6.1, предоставляет более современный и удобный API для операций JDBC.
Чтобы использовать JdbcClient
для доступа к основному хранилищу данных, просто инжектируйте его в ваш бин:
@Autowired
private JdbcClient jdbcClient;
public Map<String, BigDecimal> getCustomerAmountsByJdbcClient(CustomerGrade grade) {
return jdbcClient.sql("""
select c.NAME, sum(o.AMOUNT)
from CUSTOMER c join ORDER_ o on c.ID = o.CUSTOMER_ID
where c.GRADE = :grade
group by c.NAME
""")
.param("grade", grade.getId())
.query((ResultSet rs) -> {
Map<String, BigDecimal> result = new HashMap<>();
while (rs.next()) {
result.put(rs.getString(1), rs.getBigDecimal(2));
}
return result;
});
}
Если вам нужен доступ к дополнительному хранилищу данных, инжектируйте соответствующий javax.sql.DataSource
и создайте новый экземпляр JdbcClient
. В следующем примере JdbcClient
создается для хранилища данных db1
:
@Autowired
@Qualifier("db1DataSource")
private DataSource db1DataSource;
public List<String> loadFooNamesByJdbcClient() {
JdbcClient jdbcClient = JdbcClient.create(db1DataSource);
return jdbcClient.sql("select NAME from SAMPLE_FOO").query(String.class).list();
}
Вызов хранимых процедур
Для выполнения хранимых процедур можно использовать класс SimpleJdbcCall
из Spring. Он обеспечивает лучшую обработку параметров и поддержку метаданных базы данных по сравнению с JdbcTemplate
.
Следующий пример показывает, как вызвать хранимую процедуру PostgreSQL, находящуюся в основном хранилище данных.
CREATE OR REPLACE FUNCTION get_customer_stats(
p_customer_id UUID,
OUT total_orders INTEGER,
OUT total_amount DECIMAL(19,2)
)
LANGUAGE plpgsql
AS $$
BEGIN
SELECT
COUNT(*),
COALESCE(SUM(AMOUNT), 0)
INTO
total_orders,
total_amount
FROM ORDER_
WHERE CUSTOMER_ID = p_customer_id;
END;
$$;
@Autowired
private JdbcTemplate jdbcTemplate;
public record CustomerStats(Integer totalOrders, BigDecimal totalAmount) {
}
public CustomerStats callStoredProcedure(UUID customerId) {
// Using SimpleJdbcCall for stored procedure
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withFunctionName("get_customer_stats")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(
new SqlParameter("p_customer_id", Types.OTHER), // UUID type
new SqlOutParameter("total_orders", Types.INTEGER),
new SqlOutParameter("total_amount", Types.DECIMAL)
);
// Execute the stored procedure
Map<String, Object> result = jdbcCall.execute(customerId);
// Extract results
Integer totalOrders = (Integer) result.get("total_orders");
BigDecimal totalAmount = (BigDecimal) result.get("total_amount");
return new CustomerStats(totalOrders, totalAmount);
}
Если нужно вызвать процедуру из дополнительного хранилища данных, создайте экземпляр JdbcTemplate
для соответствующего javax.sql.DataSource
, как описано выше.