#java #hibernate #jpa #spring-data-jpa
#java #гибернация #jpa #spring-data-jpa
Вопрос:
Я использую репозиторий Spring data JPA для своего приложения. В настоящее время я использую базовые операции CRUD, предоставляемые по умолчанию репозиториями spring data jpa, и для сложных запросов соединения я пишу пользовательские запросы JPQL следующим образом:
public interface ContinentRepository extends JpaRepository<Continent, Long>
{
@Query(value = "SELECT u FROM Continent u JOIN FETCH ... WHERE u.id = ?1")
public List<Continent> findContinent(Long id);
}
В моем классе обслуживания я автоматически подключаю этот репозиторий и выполняю операции с БД.
@Service
public class MyService
{
@Autowired
public ContinentRepository cr;
public void read()
{
var result1 = cr.findContinent(1);
var result2 = cr.findContinent(2);
}
@Transactional
public void write()
{
var c = new Continent();
// setters
c = cr.save(c);
}
}
В настоящее время я просто помечаю write()
как org.springframework.transaction.annotation.Transactional
.
- Должен ли я также пометить
read()
метод сTransactional(readOnly = true)
помощью? Поскольку он выполняет только операции чтения. - Должен ли я также пометить
findContinent(Long id)
как транзакционный (только для чтения = true)? Я читал, что все методы по умолчанию помечены как транзакционные https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions - В интерфейсе репозитория я должен пометить транзакционную аннотацию на уровне метода или на уровне интерфейса. (Кроме того, я подозреваю, что большинство пользовательских методов будут доступны только для чтения)
- Хорошо ли иметь @Transactional как на уровне сервиса, так и на уровне хранилища?
Ответ №1:
- Должен ли я также пометить метод read() транзакционным (только для чтения = true)? Поскольку он выполняет только операции чтения.
На самом деле это не обязательно, однако это может привести к некоторой оптимизации в отношении потребления кэш-памяти в соответствии с this blog https://vladmihalcea.com/spring-read-only-transaction-hibernate-optimization /
- Должен ли я также пометить findContinent (длинный идентификатор) как транзакционный (только для чтения = true)? Я читал, что все методы по умолчанию помечены как транзакционные https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
Тот же ответ, что и в первом случае
- В интерфейсе репозитория я должен пометить транзакционную аннотацию на уровне метода или на уровне интерфейса. (Кроме того, я подозреваю, что большинство пользовательских методов будут доступны только для чтения)
В общем, я добавил уровень метода, потому что у меня больше контроля над параметрами, такими как откат
- Хорошо ли иметь @Transactional как на уровне сервиса, так и на уровне хранилища?
Я рекомендую вам иметь на уровне обслуживания, потому что там вы можете обновлять много таблиц (поэтому вы можете использовать много репозиториев), и вы хотите, чтобы все ваше обновление было транзакционным.
Комментарии:
1. То, что
@Transactional(readOnly = true)
избыточно, не совсем верно. Это зависит от уровня изоляции. Хотя это действительно избыточно дляREAD COMMITED
, поведение будет отличаться дляREPEATABLE READ
и более высоких уровней изоляции, где блокировки чтения не снимаются немедленно2. Если я аннотирую класс обслуживания с помощью Transactional и метод внутри этого класса обслуживания с помощью Transactional (но с другими свойствами по сравнению с транзакционной аннотацией уровня класса), то какая аннотация будет применена. Поддерживает ли транзакционная аннотация переопределяющие свойства на уровне метода?
3. Кроме того, когда один метод службы вызывает метод из другой службы, и оба имеют распространение as
REQUIRED
, но другие свойства отличаются. Например: метод с@Transactional
in service A вызывает метод с@Transactional(readOnly=true)
in service B, тогда создается ли в этом случае новая транзакция?4. В этой статье описывается приоритетный порядок, в котором будут применяться аннотации baeldung.com /… Но я не могу найти ничего подобного в spring docs.
5. @JavaLearner Если вы аннотируете службу с
@Transactional
помощью и внутри вызываете метод репозитория, аннотированный с@Transactional
помощью, тогда вам необходимо указать распространениеREQUIRED
для аннотации транзакции репо, чтобы присоединиться к уже существующей транзакции и не создавать другую. Однако вы должны проверить, поддерживает ли ваша база данных это (так и должно быть). В общем, я этого не делаю, потому что я вызываю репозитории только в службах, а классы репозиториев защищены пакетом, чтобы их нельзя было вводить в классы, расположенные за пределами их пакета.
Ответ №2:
- Должен ли я также пометить метод read() транзакционным (только для чтения = true)? Поскольку он выполняет только операции чтения.
ДА. Это хорошая практика, вы сразу узнаете, что этот метод ничего не меняет в базе данных, и, что более важно, вы отключите некоторые непреднамеренные изменения в базе данных с помощью этого метода обслуживания. Если этот метод попытается выполнить какое-либо обновление в базе данных, будет вызвано исключение и будет вызван откат.
- Должен ли я также пометить findContinent (длинный идентификатор) как транзакционный (только для чтения = true)? Я читал, что все методы по умолчанию помечены как транзакционные https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
Зависит от того, как вы его используете. Если вы всегда вызываете это из @Sevice, то нет. Я думаю, что это обычный вариант использования, насколько я знаю.
- В интерфейсе репозитория я должен пометить транзакционную аннотацию на уровне метода или на уровне интерфейса. (Кроме того, я подозреваю, что большинство пользовательских методов будут доступны только для чтения)
То же, что и 2.
- Хорошо ли иметь @Transactional как на уровне сервиса, так и на уровне хранилища?
То же, что и 2.
Комментарии:
1. Что касается # 1, это зависит от поставщика docs.spring.io/spring-framework/docs/current/javadoc-api/org /…
2. Если вы используете Spring Data и Hibernate, это верно. Я говорю из этого опыта, и это наиболее часто используемый стек. Для меня это должно быть приемлемо, если реализация не интерпретирует только для чтения. Это очень важно, когда вы работаете в больших командах.