如何杀掉空闲事务
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html 我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html
我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数据库,也没有释放线程,但是线上事务锁定等待严重,连接数暴涨,尤其在测试库这种情况很多,线上也偶有发生,于是想为MySQL增加一个杀掉空闲事务的功能。
那么如何实现呢,通过MySQL Server层有很多不确定因素,最保险还是在存储引擎层实现,我们用的几乎都是InnoDB/XtraDB,所以就基于Percona来修改了,Oracle版的MySQL也可以照着修改。
需求:
1. 一个事务启动,如果事务内最后一个语句执行完超过一个时间(innodb_idle_trx_timeout),就应该关闭链接。
2. 如果事务是纯读事务,因为不加锁,所以无害,不需要关闭,保持即可。
虽然这个思路被Percona的指出Alexey Kopytov可能存在“Even though SELECT queries do not place row locks by default (there are exceptions), they can still block undo log records from being purged.”的问题,但是我们确实有场景SELECT是绝对不能kill的,除非之后的INSERT/UPDATE/DELETE发生了,所以我根据我们的业务特点来修改。
跟Percona的Yasufumi Kinoshita和Alexey Kopytov提出过纯SELECT事务不应被kill,但通过一个参数控制的方案还没有被Alexey Kopytov接受,作为通用处理我提出了用两个变量分别控制纯读事务的空闲超时时间和有锁事务的空闲超时时间,还在等待Percona的回复,因为这个方案还在测试,就先不开放修改了,当然如果你很熟悉MYSQL源码,我提出这个思路你肯定知道怎么分成这两个参数控制了。
根据这两个需求我们来设计方法,首先想到这个功能肯定是放在InnoDB Master Thread最方便,Master Thread每秒调度一次,可以顺便检查空闲事务,然后关闭,因为在事务中操作trx->mysql_thd并不安全,所以一般来说最好在InnoDB层换成Thread ID操作,并且InnoDB中除了ha_innodb.cc,其他地方不能饮用THD,所以Master Thread中需要的线程数值,都需要在ha_innodb中计算好传递整型或布尔型返回值给master thread调用。
首先,我们要增加一个参数:idle_trx_timeout,它表示事务多久没有下一条语句发生就超时关闭。
在storage/innodb_plugin/srv/srv0srv.c的“/* plugin options */”注释下增加如下代码注册idle_trx_timeout变量。
<span style="color: #0000ff;">static</span> MYSQL_SYSVAR_LONG<span style="color: #008000;">(</span>idle_trx_timeout, srv_idle_trx_timeout, PLUGIN_VAR_RQCMDARG, <span style="color: #FF0000;">"If zero then this function no effect, if no-zero then wait idle_trx_timeout seconds this transaction will be closed"</span>, <span style="color: #FF0000;">"Seconds of Idle-Transaction timeout"</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">LONG_MAX</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">)</span><span style="color: #008080;">;</span>
代码往下找在innobase_system_variables结构体内加上:
MYSQL_SYSVAR<span style="color: #008000;">(</span>idle_trx_timeout<span style="color: #008000;">)</span>,
有了这个变量,我们需要在Master Thread(storage/innodb_plugin/srv/srv0srv.c )中执行检测函数查找空闲事务。在loop循环的if (sync_array_print_long_waits(&waiter, &sema)判断后加上这段判断
<span style="color: #0000ff;">if</span> <span style="color: #008000;">(</span>srv_idle_trx_timeout <span style="color: #000040;">&&</span> trx_sys<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> trx_t<span style="color: #000040;">*</span> trx<span style="color: #008080;">;</span> <span style="color: #0000ff;">time_t</span> now<span style="color: #008080;">;</span> rescan_idle<span style="color: #008080;">:</span> now <span style="color: #000080;">=</span> <span style="color: #0000dd;">time</span><span style="color: #008000;">(</span><span style="color: #0000ff;">NULL</span><span style="color: #008000;">)</span><span style="color: #008080;">;</span> mutex_enter<span style="color: #008000;">(</span><span style="color: #000040;">&</span>kernel_mutex<span style="color: #008000;">)</span><span style="color: #008080;">;</span> trx <span style="color: #000080;">=</span> UT_LIST_GET_FIRST<span style="color: #008000;">(</span>trx_sys<span style="color: #000040;">-</span><span style="color: #000080;">></span>mysql_trx_list<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 从当前事务列表里获取第一个事务</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">(</span>trx<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> <span style="color: #339900;"># 依次循环每个事务进行检查</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">(</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>conc_state <span style="color: #000080;">==</span> TRX_ACTIVE <span style="color: #000040;">&&</span> trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>mysql_thd <span style="color: #000040;">&&</span> innobase_thd_is_idle<span style="color: #008000;">(</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>mysql_thd<span style="color: #008000;">)</span><span style="color: #008000;">)</span> <span style="color: #008000;">{</span> <span style="color: #339900;"># 如果事务还活着并且它的状态时空闲的</span> ib_int64_t start_time <span style="color: #000080;">=</span> innobase_thd_get_start_time<span style="color: #008000;">(</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>mysql_thd<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 获取线程最后一个语句的开始时间</span> ulong thd_id <span style="color: #000080;">=</span> innobase_thd_get_thread_id<span style="color: #008000;">(</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>mysql_thd<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #339900;">#获取线程ID,因为存储引擎内直接操作THD不安全</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">(</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>last_stmt_start <span style="color: #000040;">!</span><span style="color: #000080;">=</span> start_time<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> <span style="color: #339900;"># 如果事务最后语句起始时间不等于线程最后语句起始时间说明事务是新起的</span> trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>idle_start <span style="color: #000080;">=</span> now<span style="color: #008080;">;</span> <span style="color: #339900;"># 更新事务的空闲起始时间</span> trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>last_stmt_start <span style="color: #000080;">=</span> start_time<span style="color: #008080;">;</span> <span style="color: #339900;"># 更新事务的最后语句起始时间</span> <span style="color: #008000;">}</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">(</span><span style="color: #0000dd;">difftime</span><span style="color: #008000;">(</span>now, trx<span style="color: #000040;">-</span><span style="color: #000080;">></span>idle_start<span style="color: #008000;">)</span> <span style="color: #339900;"># 如果事务不是新起的,已经执行了一部分则判断空闲时间有多长了</span> <span style="color: #000080;">></span> srv_idle_trx_timeout<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> <span style="color: #339900;"># 如果空闲时间超过阈值则杀掉链接</span> <span style="color: #ff0000; font-style: italic;">/* kill the session */</span> mutex_exit<span style="color: #008000;">(</span><span style="color: #000040;">&</span>kernel_mutex<span style="color: #008000;">)</span><span style="color: #008080;">;</span> thd_kill<span style="color: #008000;">(</span>thd_id<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 杀链接</span> <span style="color: #0000ff;">goto</span> rescan_idle<span style="color: #008080;">;</span> <span style="color: #008000;">}</span> <span style="color: #008000;">}</span> trx <span style="color: #000080;">=</span> UT_LIST_GET_NEXT<span style="color: #008000;">(</span>mysql_trx_list, trx<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 检查下一个事务</span> <span style="color: #008000;">}</span> mutex_exit<span style="color: #008000;">(</span><span style="color: #000040;">&</span>kernel_mutex<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #008000;">}</span>
其中trx中的变量是新加的,在storage/innodb_plugin/include/trx0trx.h的trx_truct加上需要的变量:
<span style="color: #0000ff;">struct</span> trx_struct<span style="color: #008000;">{</span> ... <span style="color: #0000ff;">time_t</span> idle_start<span style="color: #008080;">;</span> ib_int64_t last_stmt_start<span style="color: #008080;">;</span> ... <span style="color: #008000;">}</span>
这里有几个函数是自定义的:
ibool innobase_thd_is_idle<span style="color: #008000;">(</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">)</span><span style="color: #008080;">;</span> ib_int64_t innobase_thd_get_start_time<span style="color: #008000;">(</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">)</span><span style="color: #008080;">;</span> ulong innobase_thd_get_thread_id<span style="color: #008000;">(</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">)</span><span style="color: #008080;">;</span>
这些函数在ha_innodb.cc中实现,需要在storage/innodb_plugin/srv/srv0srv.c头文件定义下加上这些函数的引用形势。
然后在storage/innodb_plugin/handler/ha_innodb.cc 中定义这些函数的实现:
<span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">"C"</span> ibool innobase_thd_is_idle<span style="color: #008000;">(</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">)</span> <span style="color: #ff0000; font-style: italic;">/*!< in: thread handle (THD*) */</span> <span style="color: #008000;">{</span> <span style="color: #0000ff;">return</span><span style="color: #008000;">(</span><span style="color: #008000;">(</span><span style="color: #008000;">(</span><span style="color: #0000ff;">const</span> THD<span style="color: #000040;">*</span><span style="color: #008000;">)</span>thd<span style="color: #008000;">)</span><span style="color: #000040;">-</span><span style="color: #000080;">></span>command <span style="color: #000080;">==</span> COM_SLEEP<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #008000;">}</span> <span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">"C"</span> ib_int64_t innobase_thd_get_start_time<span style="color: #008000;">(</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">)</span> <span style="color: #ff0000; font-style: italic;">/*!< in: thread handle (THD*) */</span> <span style="color: #008000;">{</span> <span style="color: #0000ff;">return</span><span style="color: #008000;">(</span><span style="color: #008000;">(</span>ib_int64_t<span style="color: #008000;">)</span><span style="color: #008000;">(</span><span style="color: #008000;">(</span><span style="color: #0000ff;">const</span> THD<span style="color: #000040;">*</span><span style="color: #008000;">)</span>thd<span style="color: #008000;">)</span><span style="color: #000040;">-</span><span style="color: #000080;">></span>start_time<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #008000;">}</span> <span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">"C"</span> ulong innobase_thd_get_thread_id<span style="color: #008000;">(</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> <span style="color: #0000ff;">return</span><span style="color: #008000;">(</span>thd_get_thread_id<span style="color: #008000;">(</span><span style="color: #008000;">(</span><span style="color: #0000ff;">const</span> THD<span style="color: #000040;">*</span><span style="color: #008000;">)</span> thd<span style="color: #008000;">)</span><span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #008000;">}</span>
还有最重要的thd_kill函数负责杀线程的,在sql/sql_class.cc中,找个地方定义这个函数:
<span style="color: #0000ff;">void</span> thd_kill<span style="color: #008000;">(</span>ulong id<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> THD <span style="color: #000040;">*</span>tmp<span style="color: #008080;">;</span> VOID<span style="color: #008000;">(</span>pthread_mutex_lock<span style="color: #008000;">(</span><span style="color: #000040;">&</span>LOCK_thread_count<span style="color: #008000;">)</span><span style="color: #008000;">)</span><span style="color: #008080;">;</span> I_List_iterator<span style="color: #000080;"><</span>THD<span style="color: #000080;">></span> it<span style="color: #008000;">(</span>threads<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">(</span><span style="color: #008000;">(</span>tmp<span style="color: #000080;">=</span>it<span style="color: #000040;">++</span><span style="color: #008000;">)</span><span style="color: #008000;">)</span> <span style="color: #008000;">{</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">(</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">></span>command <span style="color: #000080;">==</span> COM_DAEMON <span style="color: #000040;">||</span> tmp<span style="color: #000040;">-</span><span style="color: #000080;">></span>is_have_lock_thd <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span> <span style="color: #008000;">)</span> <span style="color: #339900;"># 如果是DAEMON线程和不含锁的线程就不要kill了</span> <span style="color: #0000ff;">continue</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">(</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">></span>thread_id <span style="color: #000080;">==</span> id<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> pthread_mutex_lock<span style="color: #008000;">(</span><span style="color: #000040;">&</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">></span>LOCK_thd_data<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <span style="color: #008000;">}</span> <span style="color: #008000;">}</span> VOID<span style="color: #008000;">(</span>pthread_mutex_unlock<span style="color: #008000;">(</span><span style="color: #000040;">&</span>LOCK_thread_count<span style="color: #008000;">)</span><span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">(</span>tmp<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> tmp<span style="color: #000040;">-</span><span style="color: #000080;">></span>awake<span style="color: #008000;">(</span>THD<span style="color: #008080;">::</span><span style="color: #007788;">KILL_CONNECTION</span><span style="color: #008000;">)</span><span style="color: #008080;">;</span> pthread_mutex_unlock<span style="color: #008000;">(</span><span style="color: #000040;">&</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">></span>LOCK_thd_data<span style="color: #008000;">)</span><span style="color: #008080;">;</span> <span style="color: #008000;">}</span> <span style="color: #008000;">}</span>
为了存储引擎能引用到这个函数,我们要把它定义到plugin中:
include/mysql/plugin.h和include/mysql/plugin.h中加上
<span style="color: #0000ff;">void</span> thd_kill<span style="color: #008000;">(</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">long</span> id<span style="color: #008000;">)</span><span style="color: #008080;">;</span>
如何判定线程的is_have_lock_thd值?首先在THD中加上这个变量(sql/sql_class.cc):
<span style="color: #0000ff;">class</span> THD <span style="color: #008080;">:</span><span style="color: #0000ff;">public</span> Statement, <span style="color: #0000ff;">public</span> Open_tables_state <span style="color: #008000;">{</span> .... <span style="color: #007788;">uint16</span> is_have_lock_thd<span style="color: #008080;">;</span> .... <span style="color: #008000;">}</span>
然后在SQL的必经之路mysql_execute_command拦上一刀,判断是有锁操作发生了还是事务提交或新起事务。
<span style="color: #0000ff;">switch</span> <span style="color: #008000;">(</span>lex<span style="color: #000040;">-</span><span style="color: #000080;">></span>sql_command<span style="color: #008000;">)</span> <span style="color: #008000;">{</span> <span style="color: #0000ff;">case</span> SQLCOM_REPLACE<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_REPLACE_SELECT<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_UPDATE<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_UPDATE_MULTI<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_DELETE<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_DELETE_MULTI<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_INSERT<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_INSERT_SELECT<span style="color: #008080;">:</span> thd<span style="color: #000040;">-</span><span style="color: #000080;">></span>is_have_lock_thd <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">case</span> SQLCOM_COMMIT<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_ROLLBACK<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_XA_START<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_XA_END<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_XA_PREPARE<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_XA_COMMIT<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_XA_ROLLBACK<span style="color: #008080;">:</span> <span style="color: #0000ff;">case</span> SQLCOM_XA_RECOVER<span style="color: #008080;">:</span> thd<span style="color: #000040;">-</span><span style="color: #000080;">></span>is_have_lock_thd <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <span style="color: #008000;">}</span>
为了尽可能兼容Percona的补丁,能引用的都引用了Percona的操作,有些函数调用是在层次太多看不下去了就简化了。
另外还有一个版本是我自己弄的,在THD中增加了一个last_sql_end_time,在do_command结束后更新last_sql_end_time,然后在事务中拿到THD查看last_sql_end_time就可以得出idle时间,Oracle版我还是建议这么做,不要去改trx_struct结构体了,那个感觉更危险。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제









Microsoft Edge 브라우저에서 360 탐색 페이지를 여는 페이지를 변경하는 방법은 실제로 매우 간단하므로 이제 Microsoft Edge에서 360 탐색 페이지를 여는 페이지를 변경하는 방법을 공유하겠습니다. 브라우저가 필요한 친구가 모두를 도울 수 있기를 바랍니다. Microsoft Edge 브라우저를 엽니다. 아래와 같은 페이지가 보입니다. 오른쪽 상단에 있는 점 3개 아이콘을 클릭하세요. '설정'을 클릭하세요. 설정 페이지의 왼쪽 열에서 "시작 시"를 클릭하세요. 오른쪽 열의 그림에 표시된 세 지점을 클릭한 다음("새 탭 열기"를 클릭하지 마세요), 편집을 클릭하고 URL을 "0"(또는 기타 의미 없는 숫자)으로 변경하세요. 그런 다음 "저장"을 클릭하세요. 다음으로 '를 선택하세요.

다운로드한 콘텐츠를 삭제할 수 있나요? 최근 디지털 시대가 도래하면서 우리 생활에는 점점 더 많은 디지털 제품과 서비스가 등장하고 있습니다. 다음은 디지털 콘텐츠에 대한 수요가 날로 증가하고 있다는 것입니다. 일상 생활이나 업무에서 문서, 사진, 오디오, 비디오 등 다양한 파일을 다운로드해야 하는 경우가 종종 있습니다. 다운로드한 파일은 일반적으로 "다운로드"라는 폴더에 저장됩니다. 그러나 시간이 지남에 따라 우리는 종종 다음과 같은 사실을 발견하게 됩니다."

MySQL 트랜잭션 처리: 자동 제출과 수동 제출의 차이점 MySQL 데이터베이스에서 트랜잭션은 모든 실행이 성공하거나 모든 실행이 실패하여 데이터의 일관성과 무결성을 보장합니다. MySQL에서는 트랜잭션을 자동 제출과 수동 제출로 나눌 수 있는데, 차이점은 트랜잭션 제출 시기와 트랜잭션에 대한 제어 범위에 있습니다. 다음에서는 자동 제출과 수동 제출의 차이점을 자세히 소개하고 설명할 특정 코드 예제를 제공합니다. 1. 표시되지 않는 경우 MySQL에서 자동으로 제출

1G 독립 그래픽을 탑재한 i34150으로 어떤 게임을 할 수 있나요? LoL 같은 소규모 게임도 할 수 있나요? GTX750 및 GTX750TI는 매우 적합한 그래픽 카드 선택입니다. 작은 게임만 하거나 게임을 하지 않는다면 i34150 통합 그래픽 카드를 사용하는 것이 좋습니다. 일반적으로 그래픽 카드와 프로세서의 가격 차이는 그리 크지 않기 때문에 합리적인 조합을 선택하는 것이 중요합니다. 2G의 비디오 메모리가 필요한 경우 GTX750TI를 선택하는 것이 좋습니다. 1G의 비디오 메모리만 필요한 경우 GTX750을 선택하면 됩니다. GTX750TI는 오버클럭 기능을 갖춘 GTX750의 향상된 버전으로 볼 수 있습니다. i34150과 페어링할 수 있는 그래픽 카드는 필요에 따라 다릅니다. 독립형 게임을 플레이할 계획이라면 그래픽 카드 변경을 고려하는 것이 좋습니다. 당신은 선택할 수 있습니다

CheatEngine은 게임의 메모리를 편집하고 수정할 수 있는 게임 편집기입니다. 그러나 기본 언어는 중국어가 아니므로 많은 친구들에게 불편을 줍니다. 그렇다면 CheatEngine에서 중국어를 설정하는 방법은 무엇입니까? 오늘은 에디터가 CheatEngine에서 중국어를 설정하는 방법에 대해 자세히 소개하겠습니다. 도움이 되셨으면 좋겠습니다. 설정 방법 1: 1. 두 번 클릭하여 소프트웨어를 열고 왼쪽 상단에 있는 "편집"을 클릭합니다. 2. 그런 다음 아래 옵션 목록에서 "설정"을 클릭하세요. 3. 열리는 창의 왼쪽 열에서 "언어"를 클릭하세요.

다운로드 버튼을 표시하도록 Microsoft Edge가 어디에 설정되어 있는지 알고 계시나요? 아래에서 편집기를 통해 다운로드 버튼을 표시하도록 설정하는 방법을 알려드리겠습니다. 1단계: 먼저 Microsoft Edge Browser를 열고 아래 그림과 같이 오른쪽 상단에 있는 [...] 로고를 클릭합니다. 2단계: 그런 다음 아래 그림과 같이 팝업 메뉴에서 [설정]을 클릭합니다. 3단계: 그런 다음 아래 그림과 같이 인터페이스 왼쪽에 있는 [모양]을 클릭합니다. 4단계: 마지막으로 [다운로드 버튼 표시] 오른쪽에 있는 버튼을 클릭하면 아래 그림과 같이 회색에서 파란색으로 변경됩니다. 위는 편집기가 Microsoft Edge에서 다운로드 버튼을 설정하는 방법을 제공하는 곳입니다.

MySQL 트랜잭션의 원칙 및 응용 시나리오 데이터베이스 시스템에서 트랜잭션은 일련의 SQL 작업입니다. 이러한 작업은 모두 성공적으로 실행되거나 모두 실패하여 롤백됩니다. 일반적으로 사용되는 관계형 데이터베이스 관리 시스템인 MySQL은 트랜잭션 특성을 지원하며 데이터베이스의 데이터가 일관성, 격리성, 내구성 및 원자성 측면에서 보장되도록 보장할 수 있습니다. 이 기사에서는 MySQL 트랜잭션의 기본 원칙부터 시작하여 해당 애플리케이션 시나리오를 소개하고 독자가 참조할 수 있는 특정 코드 예제를 제공합니다. MySQL 트랜잭션의 원리: My

1. PDO 소개 PDO는 PHP의 확장 라이브러리로 데이터베이스를 작동하는 객체 지향 방식을 제공합니다. PDO는 Mysql, postgresql, oracle, SQLServer 등을 포함한 다양한 데이터베이스를 지원합니다. PDO를 사용하면 개발자가 통합 API를 사용하여 다양한 데이터베이스를 운영할 수 있으므로 개발자가 서로 다른 데이터베이스 간에 쉽게 전환할 수 있습니다. 2. PDO를 데이터베이스에 연결합니다. PDO를 사용하여 데이터베이스에 연결하려면 먼저 PDO 개체를 생성해야 합니다. PDO 객체의 생성자는 데이터베이스 유형, 호스트 이름, 데이터베이스 사용자 이름 및 비밀번호라는 세 가지 매개변수를 받습니다. 예를 들어, 다음 코드는 mysql 데이터베이스에 연결하는 객체를 생성합니다: $dsn="mysq
