Spring Boot+MyBatis+Atomikos+MySQL(附源碼)
Aug 15, 2023 pm 04:12 PM我們?cè)趯?shí)際專案中,盡量規(guī)避分散式交易。 但是,有些時(shí)候是真的需要做一些服務(wù)拆分從而會(huì)引出分散式事務(wù)問(wèn)題。
同時(shí),分散式事務(wù)也是面試中市場(chǎng)被問(wèn)到,可以拿著這個(gè)案例練練手,面試就可以說(shuō)上個(gè)123了。
這裡舉個(gè)業(yè)務(wù)栗子:用戶領(lǐng)取優(yōu)惠券,需要扣減用戶領(lǐng)取次數(shù),然後記錄一個(gè)用戶領(lǐng)取優(yōu)惠券記錄。


#原本這裡可以使用訊息佇列方式,採(cǎi)用非同步化去新增使用者領(lǐng)取記錄。但是,這裡需求是就是需要用戶領(lǐng)完立刻就能查看到自己的領(lǐng)取記錄,那我們這裡就引入了Atomikos
來(lái)實(shí)現(xiàn)分散式事務(wù)問(wèn)題。
分散式交易
#分散式交易是指跨越多個(gè)電腦或資料庫(kù)的事務(wù),這些電腦或資料庫(kù)之間可能存在網(wǎng)路延遲、故障或不一致的情況。分散式事務(wù)需要確保所有操作的原子性、一致性、隔離性和持久性,以確保資料的正確性和完整性。
分散式事務(wù)協(xié)定有哪些?
分散式事務(wù)協(xié)定主要有兩種:2PC(Two-Phase Commit)和3PC(Three-Phase Commit)。
2PC是目前最常用的分散式事務(wù)協(xié)議,其流程分為兩個(gè)階段:準(zhǔn)備階段和提交階段。在準(zhǔn)備階段,事務(wù)協(xié)調(diào)者向所有參與者發(fā)出準(zhǔn)備請(qǐng)求,參與者將本地事務(wù)執(zhí)行到prepare狀態(tài),並將prepare結(jié)果回傳給事務(wù)協(xié)調(diào)者。在提交階段,如果所有參與者都執(zhí)行成功,則事務(wù)協(xié)調(diào)者向所有參與者發(fā)出提交請(qǐng)求,參與者將本地事務(wù)提交,否則事務(wù)協(xié)調(diào)者向所有參與者發(fā)出回滾請(qǐng)求,參與者將本地事務(wù)回滾。
3PC是2PC的改良版,其在2PC的基礎(chǔ)上增加了一個(gè)準(zhǔn)備提交階段。在準(zhǔn)備提交階段,協(xié)調(diào)者向參與者詢問(wèn)是否可以提交,如果參與者返回同意,則在提交階段直接提交,否則在提交階段回滾。
分散式交易常見解決方案有哪些?
分散式事務(wù)解決方案有:
-
#基於訊息佇列的分散式事務(wù)方案(如RocketMQ的開源方案) 基於分散式事務(wù)框架的分散式事務(wù)方案(如Seata、TCC-Transaction等框架) 基於XA協(xié)定的分散式事務(wù)方案(如JTA等) 基於可靠訊息最終一致性的分散式事務(wù)方案(如阿里巴巴的分散式事務(wù)中間件GTS) 基於CAP原理的分散式事務(wù)方案(如CQRS架構(gòu)中的事件溯源模式)
什麼是JTA ?
JTA(Java Transaction API),是J2EE的程式介面規(guī)範(fàn),它是XA協(xié)定的JAVA實(shí)作。它主要定義了:
一個(gè)事務(wù)管理器的介面javax.transaction.TransactionManager
,定義了有關(guān)事務(wù)的開始、提交、撤回等>操作。
一個(gè)符合XA規(guī)範(fàn)的資源定義介面javax.transaction.xa.XAResource
,一個(gè)資源如果要支援JTA事務(wù),就需要讓它的資源實(shí)作該XAResource
接口,並實(shí)作該接口定義的兩階段提交相關(guān)的接口。
如果我們有一個(gè)應(yīng)用,它使用JTA介面實(shí)現(xiàn)事務(wù),應(yīng)用在運(yùn)行的時(shí)候,就需要一個(gè)實(shí)作JTA的容器,一般情況下,這是一個(gè)J2EE容器,像JBoss,Websphere等應(yīng)用伺服器。
但是,也有一些獨(dú)立的框架實(shí)作了JTA,例如Atomikos, bitronix都提供了jar包方式的JTA實(shí)作框架。這樣我們就能夠在Tomcat或Jetty之類的伺服器上運(yùn)行使用JTA實(shí)作事務(wù)的應(yīng)用系統(tǒng)。
在上面的本地事務(wù)和外部事務(wù)的區(qū)別中說(shuō)到,JTA事務(wù)是外部事務(wù),可以用來(lái)實(shí)現(xiàn)對(duì)多個(gè)資源的事務(wù)性。它正是透過(guò)每個(gè)資源實(shí)現(xiàn)的XAResource
來(lái)進(jìn)行兩階段提交的控制。有興趣的同學(xué)可以看看這個(gè)介面的方法,除了commit, rollback等方法以外,還有end()
, forget()
, isSameRM()
, prepare()
等等。光從這些介面就能夠想像JTA在實(shí)現(xiàn)兩階段事務(wù)的複雜性。
什麼是XA?
XA是由X/Open組織提出的分散式事務(wù)的架構(gòu)(或稱為協(xié)定)。 XA架構(gòu)主要定義了(全域)事務(wù)管理器(Transaction Manager)和(局部)資源管理器(Resource Manager)之間的介面。 XA介面是雙向的系統(tǒng)接口,在事務(wù)管理器(Transaction Manager)以及一個(gè)或多個(gè)資源管理器(Resource Manager)之間形成通訊橋樑。也就是說(shuō),在基於XA的一個(gè)事務(wù)中,我們可以針對(duì)多個(gè)資源進(jìn)行事務(wù)管理,例如一個(gè)系統(tǒng)存取多個(gè)資料庫(kù),或即存取資料庫(kù)、又存取像訊息中間件這樣的資源。這樣我們就能夠?qū)崿F(xiàn)在多個(gè)資料庫(kù)和訊息中間件直接實(shí)現(xiàn)全部提交、或全部取消的事務(wù)。 XA規(guī)範(fàn)不是java的規(guī)範(fàn),而是一種通用的規(guī)範(fàn), 目前各種資料庫(kù)、以及許多訊息中間件都支援XA規(guī)範(fàn)。
JTA是滿足XA規(guī)格的、用於Java開發(fā)的規(guī)格。所以,當(dāng)我們說(shuō),使用JTA實(shí)現(xiàn)分散式事務(wù)的時(shí)候,其實(shí)是說(shuō),使用JTA規(guī)範(fàn),實(shí)現(xiàn)系統(tǒng)內(nèi)多個(gè)資料庫(kù)、訊息中間件等資源的事務(wù)。
什麼是Atomikos
Atomikos是一個(gè)非常受歡迎的開源事務(wù)管理器,並且可以嵌入到你的Spring Boot應(yīng)用中。 Tomcat應(yīng)用程式伺服器沒有實(shí)作JTA規(guī)範(fàn),當(dāng)使用Tomcat作為應(yīng)用程式伺服器的時(shí)候,需要使用第三方的事務(wù)管理器類別來(lái)作為全域的事務(wù)管理器,而Atomikos框架就是這個(gè)作用,將事務(wù)管理整合到應(yīng)用程式中,而不依賴application server。
Spring Boot 整合Atomikos
說(shuō)一堆的理論沒什麼用,show me the code。
技術(shù)堆疊:Spring Boot MyBatis Atomikos MySQL
#如果你依照本文程式碼,注意你的mysql版本。
先建好兩個(gè)資料庫(kù)(my-db_0和my-db_1),然後每個(gè)庫(kù)裡各建一張表。
資料庫(kù)my-db_0中:
CREATE TABLE `t_user_0` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `age` int NOT NULL, `gender` int NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
資料庫(kù)my-db_1中:
CREATE TABLE `t_user_1` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `age` int NOT NULL, `gender` int NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
這裡只是為了示範(fàn)分散式事務(wù),不用在意表的具體意義。
整體專案結(jié)構(gòu)

maven配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tian</groupId>
<artifactId>spring-boot-atomikos</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<name>spring-boot-atomikos</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- mybatis依賴 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql依賴 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!--分布式事務(wù)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 要使生成的jar可運(yùn)行,需要加入此插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<!-- 編譯xml文件 -->
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>
properties配置server.port=9001
spring.application.name=atomikos-demo
spring.datasource.user0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.user0.url=jdbc:mysql://localhost:3306/my-db_0?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.user0.user=root
spring.datasource.user0.password=123456
spring.datasource.user1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.user1.url=jdbc:mysql://localhost:3306/my-db_1?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.user1.user=root
spring.datasource.user1.password=123456
mybatis.mapperLocations=classpath:/com/tian/mapper/*/*.xml
mybatis.typeAliasesPackage=com.tian.entity
mybatis.configuration.cache-enabled=true
#資料來(lái)源##/**
* @author tianwc 公眾號(hào):java后端技術(shù)全棧、面試專欄
* @version 1.0.0
* @date 2023年05月11日 19:38
* 博客地址:<a href="http://woaijava.cc/">博客地址</a>
* <p>
* 配置好兩個(gè)數(shù)據(jù)源
*/
@Configuration
public class DataSourceConfig {
// 將這個(gè)對(duì)象放入spring容器中(交給Spring管理)
@Bean
// 讀取 application.yml 中的配置參數(shù)映射成為一個(gè)對(duì)象
@ConfigurationProperties(prefix = "spring.datasource.user0")
public XADataSource getDataSource0() {
// 創(chuàng)建XA連接池
return new MysqlXADataSource();
}
/**
* 創(chuàng)建Atomikos數(shù)據(jù)源
* 注解@DependsOn("druidXADataSourcePre"),在名為druidXADataSourcePre的bean實(shí)例化后加載當(dāng)前bean
*/
@Bean
@DependsOn("getDataSource0")
@Primary
public DataSource dataSourcePre(@Qualifier("getDataSource0") XADataSource xaDataSource) {
//這里的AtomikosDataSourceBean使用的是spring提供的
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(xaDataSource);
atomikosDataSourceBean.setMaxPoolSize(20);
return atomikosDataSourceBean;
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.user1")
public XADataSource getDataSource1() {
// 創(chuàng)建XA連接池
return new MysqlXADataSource();
}
@Bean
@DependsOn("getDataSource1")
public DataSource dataSourceSit(@Qualifier("getDataSource1") XADataSource xaDataSource) {
//這里的AtomikosDataSourceBean使用的是spring提供的
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(xaDataSource);
return atomikosDataSourceBean;
}
}
MyBatis掃描@Configuration
@MapperScan(basePackages = {"com.tian.mapper.user0"}, sqlSessionTemplateRef = "preSqlSessionTemplate")
public class MybatisPreConfig {
@Autowired
@Qualifier("dataSourcePre")
private DataSource dataSource;
/**
* 創(chuàng)建 SqlSessionFactory
*/
@Bean
@Primary
public SqlSessionFactory preSqlSessionFactory() throws Exception{
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().
getResources("classpath*:com/tian/mapper/user0/*.xml"));
return bean.getObject();
}
/**
* 通過(guò) SqlSessionFactory 來(lái)創(chuàng)建 SqlSessionTemplate
*/
@Bean
@Primary
public SqlSessionTemplate preSqlSessionTemplate(@Qualifier("preSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
// SqlSessionTemplate是線程安全的,可以被多個(gè)DAO所共享使用
return new SqlSessionTemplate(sqlSessionFactory);
}
}
("classpath*:com/tian/mapper/user1/*.xml")
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tian.mapper.user0.User0Mapper">
<!-- -->
<cache eviction="LRU" flushInterval="10000" size="1024" />
<resultMap id="BaseResultMap" type="com.tian.entity.User0">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="user_name" jdbcType="VARCHAR" property="userName" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="gender" jdbcType="INTEGER" property="gender" />
</resultMap>
<sql id="Base_Column_List">
id, user_name, age, gender
</sql>
<insert id="insert" parameterType="com.tian.entity.User0">
insert into t_user_0 (id, user_name,age, gender)
values (#{id,jdbcType=BIGINT}, #{userName,jdbcType=VARCHAR},#{age,jdbcType=INTEGER},#{gender,jdbcType=INTEGER})
</insert>
</mapper>
另外一個(gè)基本上完全一樣,這裡就貼出來(lái)了。 public interface User0Mapper {
int insert(User0 record);
}
#service/** * @author tianwc 公眾號(hào):java后端技術(shù)全棧、面試專欄 * @version 1.0.0 * @date 2023年05月11日 19:38 * 博客地址:<a href="http://woaijava.cc/">博客地址</a> * <p> * 模擬三種場(chǎng)景:正常、制造異常、數(shù)據(jù)庫(kù)異常 */ @Service public class UserServiceImpl implements UserService { @Resource private User0Mapper user0Mapper; @Resource private User1Mapper user1Mapper; /** * 正常邏輯 同時(shí)對(duì)兩個(gè)數(shù)據(jù)庫(kù)進(jìn)行 插入數(shù)據(jù) */ @Transactional @Override public int transaction1() throws Exception { User1 user1 = new User1(); user1.setUserName("22222"); user1.setAge(11); user1.setGender(0); user1Mapper.add(user1); System.out.println("---------------------------"); // sit(數(shù)據(jù)源1) User0 user0 = new User0(); user0.setUserName("111111"); user0.setAge(11); user0.setGender(0); user0Mapper.insert(user0); return 1; } /** * 正常邏輯 同時(shí)對(duì)兩個(gè)數(shù)據(jù)庫(kù)進(jìn)行 插入數(shù)據(jù) * 數(shù)據(jù)插入完后 出現(xiàn)異常 */ @Transactional @Override public int transaction2() throws Exception { User1 user1 = new User1(); user1.setUserName("22222"); user1.setAge(11); user1.setGender(0); user1Mapper.add(user1); System.out.println("---------------------------"); // sit(數(shù)據(jù)源1) User0 user0 = new User0(); user0.setUserName("111111"); user0.setAge(11); user0.setGender(0); user0Mapper.insert(user0); //認(rèn)為制造一個(gè)異常 int a=1/0; return 1; } /** * 第一個(gè)數(shù)據(jù)插入成功 第二個(gè)數(shù)據(jù)插入失敗 */ @Transactional @Override public int transaction3() throws Exception { User1 user1 = new User1(); user1.setUserName("22222"); user1.setAge(11); user1.setGender(0); user1Mapper.add(user1); System.out.println("---------------------------"); // sit(數(shù)據(jù)源1) User0 user0 = new User0(); //故意搞長(zhǎng)點(diǎn),模擬插入失敗 讓前面的數(shù)據(jù)回滾 user0.setUserName("111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); user0.setAge(11); user0.setGender(0); user0Mapper.insert(user0); return 1; } }
## controller<pre class='brush:php;toolbar:false;'>@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@PostMapping("/test1")
public CommonResult test1() {
int i = 0;
try {
i = userService.transaction1();
return CommonResult.success(i);
} catch (Exception e) {
e.printStackTrace();
}
return CommonResult.success(i);
}
@PostMapping("/test2")
public CommonResult test2() {
int i = 0;
try {
i = userService.transaction2();
return CommonResult.success(i);
} catch (Exception e) {
e.printStackTrace();
}
return CommonResult.success(i);
}
@PostMapping("/test3")
public CommonResult test3() {
int i = 0;
try {
i = userService.transaction3();
return CommonResult.success(i);
} catch (Exception e) {
e.printStackTrace();
}
return CommonResult.success(i);
}
}</pre>
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; /** * @author tianwc 公眾號(hào):java后端技術(shù)全棧、面試專欄 * @version 1.0.0 * @date 2023年05月11日 19:38 * 博客地址:<a href="http://woaijava.cc/">博客地址</a> * <p> * 項(xiàng)目啟動(dòng)類 */ @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) //@ComponentScan(basePackages = {"com.tian"}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }########測(cè)試########################################################## #####啟動(dòng)項(xiàng)目,分別測(cè)試以下三個(gè):#########http://localhost:9001/user/test1### ? 結(jié)果:兩個(gè)資料庫(kù)中,表格資料都新增一條#########http://localhost:9001/user/test2### ? ?結(jié)果:拋出除數(shù)無(wú)法為Zero的例外,兩個(gè)資料庫(kù)都沒有新增資料。 ###
http://localhost:9001/user/test3
? ?結(jié)果:拋出資料欄位值太長(zhǎng)異常,兩個(gè)資料庫(kù)都沒有新增資料。
好了,到此我們已經(jīng)實(shí)作了分散式事務(wù)。
以上是Spring Boot+MyBatis+Atomikos+MySQL(附源碼)的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁(yè)開發(fā)工具

SublimeText3 Mac版
神級(jí)程式碼編輯軟體(SublimeText3)

1.PHP開發(fā)問(wèn)答社區(qū)首選Laravel MySQL Vue/React組合,因生態(tài)成熟、開發(fā)效率高;2.高性能需依賴緩存(Redis)、數(shù)據(jù)庫(kù)優(yōu)化、CDN和異步隊(duì)列;3.安全性必須做好輸入過(guò)濾、CSRF防護(hù)、HTTPS、密碼加密及權(quán)限控制;4.變現(xiàn)可選廣告、會(huì)員訂閱、打賞、傭金、知識(shí)付費(fèi)等模式,核心是匹配社區(qū)調(diào)性和用戶需求。

要實(shí)現(xiàn)MySQL部署自動(dòng)化,關(guān)鍵在於選用Terraform定義資源、Ansible管理配置、Git進(jìn)行版本控制,並強(qiáng)化安全與權(quán)限管理。 1.使用Terraform定義MySQL實(shí)例,如AWSRDS的版本、類型、訪問(wèn)控制等資源屬性;2.通過(guò)AnsiblePlaybook實(shí)現(xiàn)數(shù)據(jù)庫(kù)用戶創(chuàng)建、權(quán)限設(shè)置等細(xì)節(jié)配置;3.所有配置文件納入Git管理,支持變更追蹤與協(xié)作開發(fā);4.避免硬編碼敏感信息,使用Vault或AnsibleVault管理密碼,並設(shè)置訪問(wèn)控制與最小權(quán)限原則。

PHP設(shè)置環(huán)境變量主要有三種方式:1.通過(guò)php.ini全局配置;2.通過(guò)Web服務(wù)器(如Apache的SetEnv或Nginx的fastcgi_param)傳遞;3.在PHP腳本中使用putenv()函數(shù)。其中,php.ini適用於全局且不常變的配置,Web服務(wù)器配置適用於需要隔離的場(chǎng)景,putenv()適用於臨時(shí)性的變量。持久化策略包括配置文件(如php.ini或Web服務(wù)器配置)、.env文件配合dotenv庫(kù)加載、CI/CD流程中動(dòng)態(tài)注入變量。安全管理敏感信息應(yīng)避免硬編碼,推薦使用.en

收集用戶行為數(shù)據(jù)需通過(guò)PHP記錄瀏覽、搜索、購(gòu)買等信息至數(shù)據(jù)庫(kù),並清洗分析以挖掘興趣偏好;2.推薦算法選擇應(yīng)根據(jù)數(shù)據(jù)特徵決定:基於內(nèi)容、協(xié)同過(guò)濾、規(guī)則或混合推薦;3.協(xié)同過(guò)濾在PHP中可實(shí)現(xiàn)為計(jì)算用戶餘弦相似度、選K近鄰、加權(quán)預(yù)測(cè)評(píng)分並推薦高分商品;4.性能評(píng)估用準(zhǔn)確率、召回率、F1值及CTR、轉(zhuǎn)化率並通過(guò)A/B測(cè)試驗(yàn)證效果;5.冷啟動(dòng)問(wèn)題可通過(guò)商品屬性、用戶註冊(cè)信息、熱門推薦和專家評(píng)價(jià)緩解;6.性能優(yōu)化手段包括緩存推薦結(jié)果、異步處理、分佈式計(jì)算與SQL查詢優(yōu)化,從而提升推薦效率與用戶體驗(yàn)。

為什麼需要SSL/TLS加密MySQL連接?因?yàn)椴患用艿倪B接可能導(dǎo)致敏感數(shù)據(jù)被截取,啟用SSL/TLS可防止中間人攻擊並滿足合規(guī)要求;2.如何為MySQL配置SSL/TLS?需生成證書和私鑰,修改配置文件指定ssl-ca、ssl-cert和ssl-key路徑並重啟服務(wù);3.客戶端連接時(shí)如何強(qiáng)制使用SSL?通過(guò)創(chuàng)建用戶時(shí)指定REQUIRESSL或REQUIREX509實(shí)現(xiàn);4.SSL配置容易忽略的細(xì)節(jié)包括證書路徑權(quán)限、證書過(guò)期問(wèn)題以及客戶端配置需求。

要使用REVOKE回收MySQL用戶權(quán)限,需按格式指定權(quán)限類型、數(shù)據(jù)庫(kù)和用戶。 1.回收全部權(quán)限用REVOKEALLPRIVILEGES,GRANTOPTIONFROM'用戶名'@'主機(jī)名';2.回收特定數(shù)據(jù)庫(kù)權(quán)限用REVOKEALLPRIVILEGESONmydb.FROM'用戶名'@'主機(jī)名';3.回收全局權(quán)限用REVOKE權(quán)限類型ON.*FROM'用戶名'@'主機(jī)名';注意執(zhí)行後建議刷新權(quán)限,權(quán)限範(fàn)圍需與授權(quán)時(shí)一致,且不能回收不存在的權(quán)限。

PHP在智能客服中扮演連接器和大腦中樞角色,負(fù)責(zé)串聯(lián)前端輸入、數(shù)據(jù)庫(kù)存儲(chǔ)與外部AI服務(wù);2.實(shí)現(xiàn)時(shí)需構(gòu)建多層架構(gòu):前端接收用戶消息,PHP後端預(yù)處理並路由請(qǐng)求,先匹配本地知識(shí)庫(kù),未命中則調(diào)用外部AI服務(wù)如OpenAI或Dialogflow獲取智能回復(fù);3.會(huì)話管理由PHP寫入MySQL等數(shù)據(jù)庫(kù),保障上下文連續(xù)性;4.集成AI服務(wù)需用Guzzle發(fā)送HTTP請(qǐng)求,安全存儲(chǔ)APIKey,做好錯(cuò)誤處理與響應(yīng)解析;5.數(shù)據(jù)庫(kù)設(shè)計(jì)需包含會(huì)話、消息、知識(shí)庫(kù)、用戶表,合理建索引、保障安全與性能,支撐機(jī)器人記憶

選擇合適的PHP框架需根據(jù)項(xiàng)目需求綜合考慮:Laravel適合快速開發(fā),提供EloquentORM和Blade模板引擎,便於數(shù)據(jù)庫(kù)操作和動(dòng)態(tài)表單渲染;Symfony更靈活,適合複雜系統(tǒng);CodeIgniter輕量,適用於對(duì)性能要求較高的簡(jiǎn)單應(yīng)用。 2.確保AI模型準(zhǔn)確性需從高質(zhì)量數(shù)據(jù)訓(xùn)練、合理選擇評(píng)估指標(biāo)(如準(zhǔn)確率、召回率、F1值)、定期性能評(píng)估與模型調(diào)優(yōu)入手,並通過(guò)單元測(cè)試和集成測(cè)試保障代碼質(zhì)量,同時(shí)持續(xù)監(jiān)控輸入數(shù)據(jù)以防止數(shù)據(jù)漂移。 3.保護(hù)用戶隱私需採(cǎi)取多項(xiàng)措施:對(duì)敏感數(shù)據(jù)進(jìn)行加密存儲(chǔ)(如AES
