оригинал:190623 - Обновление Объявления Озера JPA в Учебниках серии Springboot
Выше два поста в блоге приоткрыли угол завесы использования jpa.Далее продолжим тянуть вниз.После того как данные будут вставлены в бд,это не значит что они останутся без изменений.Сэкономлены деньги в нем, и есть деньги на вывод (особенно, когда банковская процентная ставка такая низкая, лучше покупать биткойны, по состоянию на 22.06.19, btc превысил 1,1w$, но, к сожалению, нет денег, чтобы купить 😭) Это наша сегодняшняя тема, обновление данных -- как использовать обновление
Благодаря этому сообщению в блоге вы можете, по крайней мере, получить
-
save()
Измените запись непосредственно в соответствии с идентификатором - использовать
jpl
Реализовать использование модификации запроса - Тайна первого познания вещей
I. Подготовка окружающей среды
Прежде чем начать, конечно, вы должны подготовить базовую среду, такую как использование mysql для установки и тестирования, создание проектов проектов SpringBoot, настройка информации о конфигурации и т. д. Подробную информацию о создании проектов см. в предыдущей статье.
- 190612-Руководство по серии SpringBoot Создание базовой среды JPA
- 190614-Добавлена новая запись с использованием положения JPA в руководствах серии SpringBoot.
Давайте кратко посмотрим на конфигурацию, необходимую в процессе добавления записей.
1. подготовить стол
Следуя таблице предыдущей статьи, структура выглядит следующим образом.
CREATE TABLE `money` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
`money` int(26) NOT NULL DEFAULT '0' COMMENT '钱',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
2. Конфигурация проекта
Информация о конфигурации немного отличается от предыдущей. Мы добавили более подробную печать журнала; основная цель этой статьи — сосредоточиться на использовании состояния добавления записей. Инструкции по настройке мы объясним отдельно позже.
## DataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=
## jpa相关配置
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
3. Подготовка данных
Модификация данных, поэтому мы сначала вставляем две части данных в таблицу для последующих операций.
INSERT INTO `money` (`id`, `name`, `money`, `is_deleted`, `create_at`, `update_at`)
VALUES
(21, 'jpa 修改->一灰灰', 1212, 0, '2019-06-22 21:41:13', '2019-06-22 21:41:13'),
(22, 'jpa 修改->一灰灰', 6666, 0, '2019-06-22 21:41:13', '2019-06-22 21:41:13');
II. Обновить учебное пособие
Начнем входить в тему.Для удобства студентов, которые читают ее впервые (студентов, у которых нет времени или неинтересно читать предыдущие сообщения блога), будет некоторый контент, который совпадает с предыдущим сообщения в блоге. Пожалуйста, игнорируйте, если вы его читали.
1. Ассоциация таблиц POJO
Предыдущая вставка представила пошаговый процесс создания POJO, и были определены соответствующие аннотации.Результаты размещены непосредственно ниже.
@Data
@DynamicInsert
@Entity
@Table(name = "money")
public class MoneyPO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "money")
private Long money;
@Column(name = "is_deleted")
private Byte isDeleted;
@Column(name = "create_at")
@CreatedDate
private Timestamp createAt;
@Column(name = "update_at")
@CreatedDate
private Timestamp updateAt;
}
Несколько аннотаций в приведенном выше классе описываются следующим образом.
-
@Data
Он относится к аннотации Ломбок, не имеет ничего общего с JPA и автоматически генерируетсяgetter/setter/equals/hashcode/tostring
И другие методы -
@Entity
,@Table
Аннотация jpa указывает, что этот класс связан с таблицей db, а конкретное совпадение — это таблицаmoney
-
@Id
@GeneratedValue
Функция и автоинкрементный первичный ключ -
@Column
Указывает, что этот атрибут соответствует столбцу в таблице -
@CreateDate
Создание метки времени по умолчанию на основе текущего времени
2. Объявление API репозитория
Далее мы создаем новый API, который наследуется отCurdRepository
, а затем использовать этот API для работы с базой данных
public interface MoneyUpdateRepository extends CrudRepository<MoneyPO, Integer> {
}
3. Используйте осанку
a. save
В предыдущем сообщении в блоге мы знаем, что, когда идентификатор POJO существует, может быть два случая для вызова метода сохранения.
- Если поле, соответствующее этому идентификатору в БД, не существует, вставьте
- Если поле, соответствующее этому идентификатору в БД, существует, обновите
Давайте попробуем эффект обновления, Следующий код демонстрирует два блока, один — это то, что происходит, когда все значения членов в po действительны, и одно из них обновляется; другое — это то, что происходит, когда часть обновления (имя пусто) , что указывает на то, что я не хочу обновлять имя)
public void simpleUpdateById() {
MoneyPO record = moneyUpdateRepository.findById(21).get();
// 直接修改这个record的内容
record.setMoney(3333L);
moneyUpdateRepository.save(record);
record = moneyUpdateRepository.findById(21).get();
System.out.println("after updateMoney record: " + record);
record.setName(null);
record.setMoney(6666L);
moneyUpdateRepository.save(record);
record = moneyUpdateRepository.findById(21).get();
System.out.println("after updateMoney record: " + record);
}
Результаты вывода показали, что предыдущее выполнение было успешным, а последнее выполнение не удалось.
Вышеуказанное является первым результатом выполнения. От сращенного SQL мы можем знать, что это полная модификация; результат вывода, как мы ожидали.
Установив пустое имя, снова обновите его и обнаружите, что возникает исключение, как показано ниже, это из-за наших ограничений базы данных, поле не допускает существования нуля
Из сплайсированного sql мы знаем, что это потому, что каждый элемент действует какupdate sql
Член семьи, мы также столкнулись с аналогичной проблемой в статье вставки, когда мы добавили аннотации к POJO.@DynamicInsert
, выбирайте вставлять по фактическим потребностям, то есть ли в обновлении подобная аннотация?
@Data
@DynamicUpdate
@DynamicInsert
@Entity
@Table(name = "money")
public class MoneyPO {
}
Добавьте аннотации к pojo@DynamicUpdate
После этого попробуйте еще раз, и результат будет следующим
На самом деле, это все еще не удалось, из вывода SQL, на самом делеname
иmoney
Все они рассматриваются как часть SQL, потому что мы вызываем метод setter. Ожидание, чтобы угадать, сделать это снова
MoneyPO toUpdate = new MoneyPO();
toUpdate.setId(21);
toUpdate.setMoney(6666L);
moneyUpdateRepository.save(toUpdate);
record = moneyUpdateRepository.findById(21).get();
System.out.println("after updateMoney record: " + record);
Вывод следующий.Кажется, что наша догадка выше неверна.Сплайсинг sql должен основываться на том, какое поле изменилось, и какое из них должно использоваться как часть sql.
После прочтения приведенного выше положения возникнет четкое ощущение, что поддержка этого обновления должна сначала получить целевой объект, а затем изменить его, что трудно соответствовать нашим повседневным бизнес-сценариям;
б. Обновление запроса
Довольно часто обновляются соответствующие данные по определенному условию, в jpa нет возможности поддерживать такого рода сцены по названию метода, но обнаруживается еще одна интересная вещь--jql
Напрямую добавить аннотацию, аннотировать внутреннюю запись SQL
/**
* 根据金钱来修改状态
*
* @param money
* @param state
*/
@Modifying
@Query("update MoneyPO m set m.isDeleted=?2 where m.money=?1")
void updateStateByMoney(Long money, Byte state);
/**
* 表达式计算
*
* @param id
* @param money
*/
@Modifying
@Query("update MoneyPO m set m.money=m.money + ?2 where m.id=?1")
void addMoneyById(Integer id, Long money);
Вышеуказанное обязательство обновления случая, обратите внимание на два примечания
-
@Modifying
Это должно быть, сообщает фреймворку, что мы выполняем операцию обновления/удаления. -
@Query
Внутри обычный оператор sql, но следует отметить, что имя таблицы — это не фактическая таблица, а POJO, который мы определили ранее.
Затем протестируйте с помощью
public void updateByQuery() {
// 通过查询修改
moneyUpdateRepository.updateStateByMoney(6666L, (byte) 0x01);
MoneyPO record = moneyUpdateRepository.findById(21).get();
System.out.println("after update record: " + record);
moneyUpdateRepository.addMoneyById(21, 3333L);
record = moneyUpdateRepository.findById(21).get();
System.out.println("after addMoney record: " + record);
}
Выполните приведенный выше код, к сожалению, обнаружено, что сообщается об ошибкеCaused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
Из описания стека обновление/удаление должно запускать транзакцию, так что же такое транзакция? Вот несколько рекомендуемых постов в блоге
- MySQL Lock и детали транзакции
- Используйте положение весенних дел
- Управление транзакциями и свойства распространения Spring Learning
Что касается других проблем, связанных с транзакциями в jpa, мы представим их позже.Давайте вернемся к теме этой статьи и к тому, как решить проблему: просто добавьте аннотации транзакций к вышеуказанным методам.
@Transactional
public void testUpdate() {
simpleUpdateById();
updateByQuery();
}
После повторного выполнения результат следующий
Глядя на приведенные выше результаты, обнаруживается, что результат вывода после money+3333 по-прежнему равен 6666, но если мы снова посмотрим на результат db, то он уже будет 9999. Почему это так?
Интереснее вопрос выше.Первоначальная догадка связана с внутренним механизмом кеширования jpa.Что касается так ли это,нужно открыть дырку,чтобы проверить один или два.
4. Резюме
Используя JPA для обновления данных таблицы, вышеизложенное в основном вводит два метода, сохранить + JQL
save
При обновлении через сохранение нужно указать id для модификации одной записи
jql
Синтаксис аналогичен sql, но с двумя аннотациями.@Modifying
, @Query
Чтобы использовать следующий пример, необходимо обратить внимание на два момента
- Имя таблицы — это POJO, который мы определили для связи с таблицей в БД.
- Формат передачи параметров такой
?index
, index - это позиция параметра
@Modifying
@Query("update MoneyPO m set m.isDeleted=?2 where m.money=?1")
void updateStateByMoney(Long money, Byte state);
Для модификации и удаления данных необходимо отображать транзакцию оператора, иначе будет сообщено об ошибке.Одним из них является добавление аннотаций к вызываемому методу.@Transactional
, либо добавить аннотации прямо в интерфейс API репозитория@Transactional
II. Другое
0. Исходный код и связанные сообщения в блоге
исходный код
- проект:GitHub.com/JuneB/tickets…
- module: GitHub.com/JuneB/tickets…
Связанный Боуэн
- блокировка mysql и детали транзакции
- Использование позы весенних учебных дел
- Управление транзакциями и свойства распространения Spring Learning
- 190612-Руководство по серии SpringBoot Создание базовой среды JPA
- 190614-Добавлена новая запись с использованием положения JPA в руководствах серии SpringBoot.
1. Серый блог
Это не так хорошо, как письмо. Вышеупомянутое содержание чисто из семьи. Из-за ограниченных личных способностей неизбежно будут упущения и ошибки. Если вы обнаружите ошибки или у вас есть лучшие предложения, вы можете критиковать и поправьте их.
Ниже представлен серый личный блог, в котором записываются все посты в блоге по учебе и работе, приглашаю всех посетить
- One Grey BlogПерсональный блогblog.hhui.top
- Серый блог - специальный весенний блогspring.hhui.top