Eloquent ORM 非常好,尽管我想知道是否有一种简单的方法可以像 PDO 一样使用 innoDB 设置 MySQL 事务,或者我是否必须扩展 ORM 才能实现这一点?
你可以这样做:
DB::transaction(function() {
//
});
闭包内的所有内容都在事务中执行。如果发生异常会自动回滚。
如果你不喜欢匿名函数:
try {
DB::connection()->pdo->beginTransaction();
// database queries here
DB::connection()->pdo->commit();
} catch (\PDOException $e) {
// Woopsy
DB::connection()->pdo->rollBack();
}
更新:对于 laravel 4,
pdo
对象不再公开,所以:
try {
DB::beginTransaction();
// database queries here
DB::commit();
} catch (\PDOException $e) {
// Woopsy
DB::rollBack();
}
如果您想避免关闭,并乐意使用外观,以下内容可以使事情保持美观和干净:
try {
\DB::beginTransaction();
$user = \Auth::user();
$user->fill($request->all());
$user->push();
\DB::commit();
} catch (Throwable $e) {
\DB::rollback();
}
如果任何语句失败,提交将永远不会命中,并且事务将不会处理。
如果你想使用Eloquent,你也可以使用这个
这只是我项目中的示例代码
/*
* Saving Question
*/
$question = new Question;
$questionCategory = new QuestionCategory;
/*
* Insert new record for question
*/
$question->title = $title;
$question->user_id = Auth::user()->user_id;
$question->description = $description;
$question->time_post = date('Y-m-d H:i:s');
if(Input::has('expiredtime'))
$question->expired_time = Input::get('expiredtime');
$questionCategory->category_id = $category;
$questionCategory->time_added = date('Y-m-d H:i:s');
DB::transaction(function() use ($question, $questionCategory) {
$question->save();
/*
* insert new record for question category
*/
$questionCategory->question_id = $question->id;
$questionCategory->save();
});
我确定您不是在寻找封闭解决方案,请尝试使用更紧凑的解决方案
try{
DB::beginTransaction();
/*
* Your DB code
* */
DB::commit();
}catch(\Exception $e){
DB::rollback();
}
由于某种原因,很难在任何地方找到这些信息,所以我决定将其发布在这里,因为我的问题虽然与 Eloquent 事务相关,但正是改变了这一点。
阅读完THIS stackoverflow 答案后,我意识到我的数据库表使用的是 MyISAM 而不是 InnoDB。
要使事务在 Laravel(或其他任何地方)上运行,需要将表设置为使用 InnoDB
为什么?
引用 MySQL 事务和原子操作文档(此处):
MySQL 服务器(版本 3.23-max 以及所有版本 4.0 及更高版本)支持使用 InnoDB 和 BDB 事务存储引擎进行事务。 InnoDB 提供完全的 ACID 合规性。请参阅第 14 章,存储引擎。有关 InnoDB 在事务错误处理方面与标准 SQL 的差异的信息,请参阅第 14.2.11 节“InnoDB 错误处理”。
MySQL Server 中的其他非事务性存储引擎(例如 MyISAM)遵循不同的数据完整性范例,称为“原子操作”。在事务方面,MyISAM 表实际上始终以 autocommit = 1 模式运行。原子操作通常可以提供相当的完整性和更高的性能。
由于 MySQL Server 支持这两种范例,因此您可以决定您的应用程序是否最适合原子操作的速度或使用事务功能。可以根据每个表进行此选择。
如果发生任何异常,事务将自动回滚。
Laravel 基本交易格式
try{
DB::beginTransaction();
/*
* SQL operation one
* SQL operation two
..................
..................
* SQL operation n */
DB::commit();
/* Transaction successful. */
}catch(\Exception $e){
DB::rollback();
/* Transaction failed. */
}
最好最清晰的方法:
DB::beginTransaction();
try {
DB::insert(...);
DB::insert(...);
DB::insert(...);
DB::commit();
// all good
} catch (\Exception $e) {
DB::rollback();
// something went wrong
}
public function update(Request $request, string $id)
{
$validatedData = $request->validate([
// Hospitals validation
'hospital_name' => ['required', 'string', 'max:255'],
'hospital_group' => ['nullable', 'string', 'max:255'],
'timezone' => ['nullable', 'string', 'max:255'],
'date_format' => ['nullable', 'string', 'max:50'],
'fax_number' => ['nullable', 'regex:/^\+?[0-9]{6,15}$/'],
'hospital_code' => ['nullable', 'string', 'max:100'],
// Hospital Contacts
'contact_title' => ['nullable', 'string', 'max:255'],
'contact_phone_number' => ['nullable', 'regex:/^\+?[0-9]{6,15}$/'],
'contact_fax_number' => ['nullable', 'regex:/^\+?[0-9]{6,15}$/'],
'contact_email' => ['nullable', 'email', 'max:255'],
// Hospital PACS Infos
'destination_ae_title' => ['nullable', 'string', 'max:255'],
'allowed_institution_name' => ['nullable', 'string', 'max:255'],
'allowed_ae_title' => ['nullable', 'string', 'max:255'],
'allowed_host_names' => ['nullable', 'string', 'max:255'],
// Hospital Route Nodes
'node_description' => ['nullable', 'string', 'max:255'],
'host_name' => ['required', 'string', 'max:255'],
'ae_title' => ['required', 'string', 'max:255'],
'port' => ['required', 'integer', 'between:1,65535'],
]);
// Start Transaction
DB::beginTransaction();
try {
// Fetch the existing hospital
$hospital = Hospital::findOrFail($id);
// Update Hospital Data
$hospital->update([
'hospital_name' => $request->input('hospital_name'),
'hospital_group' => $request->input('hospital_group'),
'timezone' => $request->input('timezone'),
'date_format' => $request->input('date_format'),
'fax_number' => $request->input('fax_number'),
'hospital_code' => $request->input('hospital_code'),
]);
// Update Hospital Contact
$hospital->hospitalContact()->updateOrCreate(
['hospital_id' => $hospital->id],
[
'contact_title' => $request->input('contact_title'),
'contact_phone_number' => $request->input('contact_phone_number'),
'contact_email' => $request->input('contact_email'),
]
);
// Update Hospital Route Node
$hospital->hospitalRouteNode()->updateOrCreate(
['hospital_id' => $hospital->id],
[
'node_description' => $request->input('node_description'),
'host_name' => $request->input('host_name'),
'ae_title' => $request->input('ae_title'),
'port' => $request->input('port'),
]
);
// Update Hospital PACS Info
$hospital->hospitalPacsInfo()->updateOrCreate(
['hospital_id' => $hospital->id],
[
'destination_ae_title' => $request->input('destination_ae_title'),
'allowed_institution_name' => $request->input('allowed_institution_name'),
'allowed_ae_title' => $request->input('allowed_ae_title'),
'allowed_host_name' => $request->input('allowed_host_name'),
'is_promiscuous' => $request->has('is_promiscuous'),
]
);
// Update Hospital Modality
$hospital->hospitalModality()->updateOrCreate(
['hospital_id' => $hospital->id],
[
'cr' => $request->has('cr'),
'ct' => $request->has('ct'),
'dx' => $request->has('dx'),
'ecg' => $request->has('ecg'),
'mg' => $request->has('mg'),
'mr' => $request->has('mr'),
'pathology' => $request->has('pathology'),
'us' => $request->has('us'),
]
);
// Commit Transaction
DB::commit();
return redirect()->route('ListAllStudySources.index')
->with('success', 'Hospital update successfully');
} catch (\Exception $e) {
DB::rollBack();
return redirect()->back()->with('error', 'Failed to update hospital: ' . $e->getMessage());
}
}