自定义一个简单的 ORM 框架(orm框架的原理是什么)
ccwgpt 2024-09-17 12:27 25 浏览 0 评论
自定义一个简单的 ORM 框架
前面我们通过跟踪源码的方式剖析了Hibernate 和MyBatis 两个框架是如何应用 ORM 思想的,接下来我们自己定义一个简单的 ORM 框架(名为 MiniORM),希望能通过这种方式让大家亲自零距离的去应用一下 ORM。
4.1MiniORM 框架的结构设计
1.第一层为配置层:
?miniORM.cfg.xml 是框架的核心配置文件,主要用来设置数据库连接信息和映射配置文件路径信息
?Xxx.mapper.xml 是框架的映射配置文件,主要用来设置类和表之间以及属性和字段之间的映射关系
?Xxx.java 是带有映射注解的实体类,主要用来设置类和表之间以及属性和字段之间的映射关系,和 Xxx.mapper.xml 的作用一样,只不过采用的是注解方式,两者二选一
2.第二层为解析层:
?Dom4jUtil 类用来解析 miniORM.cfg.xml 和Xxx.mapper.xml 两个配置文件的数据
?AnnotationUtil 类用来解析实体类中的映射注解
3.第三层为封装层:
?ORMConfig 类用来封装和存储从 miniORM.cfg.xml 文件中解析得到的数据
?Mapper 类用来封装和存储从 Xxx.mapper.xml 或实体类中解析得到的映射数据
4.第四层为功能层:
?ORMSession 类主要用来从 ORMConfig 和 Mapper 中获取相关数据,然后生成 sql 语句, 最后通过对 JDBC 的封装最终实现增删改查功能
4.2MiniORM 框架的代码实现
1.pom.xml
<groupId>cn.itcast.framework.miniorm</groupId>
<artifactId>MiniORM</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<finalName>MiniORM</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<bootclasspath>${JAVA_HOME}/jre/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
MiniORM 框架依赖 dom4j 和 jdk1.8, 编译时会打成 jar 包并 install 到本地仓库中,如下图所示:
2.miniORM.cfg.xml 是框架的核心配置文件,主要用来设置数据库连接信息和映射配置文件路径信息,源码如下所示:
<?xml version='1.0' encoding='utf-8'?> <orm-factory> <!--数据库连接数据--> <property name="connection.url">jdbc:mysql://localhost:3306/test</property> <property name="connection.driverClass">com.mysql.jdbc.Driver</property> <property name="connection.username">root</property> <property name="connection.password">123</property> <!--采用 xml 配置映射数据--> <mapping resource="cn/itcast/orm/test/entity/Book.mapper.xml"/> <!--采用实体类注解配置映射数据--> <entity package="cn.itcast.orm.test.entity"/> </orm-factory>
3.Xxx.mapper.xml 是框架的映射配置文件,主要用来设置类和表之间以及属性和字段之间的映射关系,以Book.mapper.xml 为例,源码如下所示:
<?xml version='1.0' encoding='UTF-8'?> <!--实体类和表之间的映射关系配置--> <orm-mapping> <class name="cn.itcast.orm.test.entity.Book" table="t_book"> <id name="id" column="bid"/> <property name="name" column="bname"/> <property name="author" column="author"/> <property name="price" column="price"/> </class> </orm-mapping>
4.当然 MiniORM 框架也支持在实体类上以注解方式去配置映射关系,以 Book.java 为例,源码如下所示:
import cn.itcast.orm.annotation.ORMColumn; import cn.itcast.orm.annotation.ORMId; import cn.itcast.orm.annotation.ORMTable; //实体类:图书@ORMTable(name = "t_book") public class Book { @ORMId @ORMColumn(name = "bid") private int id; //主键 @ORMColumn(name="bname") private String name; //图书名字 @ORMColumn(name="author") private String author; //图书作者 @ORMColumn(name="price") private double price; //图书价格 ... ... }
实体类中的@ORMTable、@ORMId、@ORMColumn 是我们自定义的三个注解,@ORMTable 用来设置当前类和哪个表对应,@ORMColumn 用来设置当前属性和表中哪个字段对应, @ORMId 用来设置哪个属性对应的字段是主键。
5.Dom4jUtil 类是一个基于 Dom4j 的工具类, 主要用来解析 miniORM.cfg.xml 和Xxx.mapper.xml,源码如下所示:
public class Dom4jUtil {
/**
*通过文件的路径获取 xml 的 document 对象
*
*@param path 文件的路径
*@return 返回文档对象
*/
public static Document getXMLByFilePath(String path) { if (null == path) {
return null;
}
Document document = null; try {
SAXReader reader = new SAXReader(); document = reader.read(new File(path));
} catch (Exception e) { e.printStackTrace();
}
return document;
}
/**
*获得某文档中某元素内某属性的值和元素的文本信息
*
*@param documentxml 文档对象
*@param elementName 元素名
*@param attrName属性名
*@return 返回一个 Map 集合
*/
public static Map<String, String> Elements2Map(Document document, String elementName,
String attrName) {
List<Element> propList = document.getRootElement().elements(elementName); Map<String, String> propConfig = new HashMap<>();
for (Element element : propList) {
String key = element.attribute(attrName).getValue(); String value = element.getTextTrim(); propConfig.put(key, value);
}
return propConfig;
}
/**
*针对 mapper.xml 文件,获得映射信息并存到 Map 集合中
*@param document xml 文档对象
*@return 返回一个 Map 集合
*/
public static Map<String, String> Elements2Map(Document document) { Element classElement = document.getRootElement().element("class"); Map<String, String> mapping = new HashMap<>();
Element idElement = classElement.element("id"); String idKey = idElement.attribute("name").getValue();
String idValue = idElement.attribute("column").getValue();
mapping.put(idKey, idValue);
List<Element> propElements = classElement.elements("property"); for (Element element : propElements) {
String propKey = element.attribute("name").getValue(); String propValue = element.attribute("column").getValue(); mapping.put(propKey, propValue);
}
return mapping;
}
/**
*针对 mapper.xml 文件,获得主键的映射信息并存到 Map 集合中
*
*@param document xml 文档对象
*@return 返回一个 Map 集合
*/
public static Map<String, String> ElementsID2Map(Document document) { Element classElement = document.getRootElement().element("class"); Map<String, String> mapping = new HashMap<>();
Element idElement = classElement.element("id"); String idKey = idElement.attribute("name").getValue();
String idValue = idElement.attribute("column").getValue(); mapping.put(idKey, idValue);
return mapping;
}
/**
*获得某文档中某元素内某属性的值
*
*@param documentxml 文档对象
*@param elementName 元素名
*@param attrName属性名
*@return 返回一个 Set 集合
*/
public static Set<String> Elements2Set(Document document, String elementName, String attrName) { List<Element> mappingList = document.getRootElement().elements(elementName);
Set<String> mappingSet = new HashSet<>(); for (Element element : mappingList) {
String value = element.attribute(attrName).getValue(); mappingSet.add(value);
}
return mappingSet;
}
/**
*获得某文档中某元素内某属性的值
*
*@param documentxml 文档对象
*@param elementName 元素名
*@param attrName属性名
*@return 返回一个 Set 集合
*/
public static String getPropValue(Document document, String elementName, String attrName) { Element element = (Element) document.getRootElement().elements(elementName).get(0); return element.attribute(attrName).getValue();
}
}
6.AnnotationUtil 类主要用来通过反射技术解析实体类中的注解,从而获得映射数据,源码如下所示:
public class AnnotationUtil {
/*
得到的类名
*/
public static String getClassName(Class clz) { return clz.getName();
}
/*
得到ORMTable 注解中的表名
*/
public static String getTableName(Class clz) {
if (clz.isAnnotationPresent(ORMTable.class)) {
ORMTable ormTable = (ORMTable) clz.getAnnotation(ORMTable.class); return ormTable.name();
} else {
System.out.println("缺少 ORMTable 注解"); return null;
}
}
/*
得到主键属性和对应的字段
*/
public static Map<String, String> getIdMapper(Class clz) { boolean flag = true;
Map<String, String> map = new HashMap<>(); Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(ORMId.class)) { flag = false;
String fieldName = field.getName();
if (field.isAnnotationPresent(ORMColumn.class)) {
ORMColumn ormColumn = field.getAnnotation(ORMColumn.class); String columnName = ormColumn.name();
map.put(fieldName, columnName); break;
} else {
System.out.println("缺少 ORMColumn 注解");
}
}
}
if (flag) {
System.out.println("缺少 ORMId 注解");
}
return map;
}
/*
得到类中所有属性和对应的字段
*/
public static Map<String, String> getPropMapping(Class clz) { Map<String, String> map = new HashMap<>(); map.putAll(getIdMapper(clz));
Field[] fields = clz.getDeclaredFields(); for (Field field : fields) {
if (field.isAnnotationPresent(ORMColumn.class)) {
ORMColumn ormColumn = field.getAnnotation(ORMColumn.class); String fieldName = field.getName();
String columnName = ormColumn.name(); map.put(fieldName, columnName);
}
}
return map;
}
/*
获得某包下面的所有类名
*/
public static Set<String> getClassNameByPackage(String packagePath) { Set<String> names = new HashSet<>();
String packageFile = packagePath.replace(".", "/");
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); if (classpath == null) {
classpath = Thread.currentThread().getContextClassLoader().getResource("/").getPath();
}
try {
classpath = java.net.URLDecoder.decode(classpath, "utf-8");
} catch (UnsupportedEncodingException e) { e.printStackTrace();
}
File dir = new File(classpath + packageFile); if (dir.exists()) {
File[] files = dir.listFiles(); for (File f : files) {
String name = f.getName();
if (f.isFile() && name.endsWith(".class")) {
name = packagePath + "." + name.substring(0, name.lastIndexOf(".")); names.add(name);
}
}
} else {
System.out.println("包路径不存在");
}
return names;
}
}
7.Mapper 类用来封装并存储从 Xxx.mapper.xml 中或从实体类中解析得到的映射信息,哪个表和哪个类映射,哪个字段和哪个属性映射等等,源码如下所示:
public class Mapper { private String className; //类名private String tableName; //表名 private Map<String,String> idMapper=new HashMap(); //主键字段和属性private Map<String,String> propMapping=new HashMap(); //非主键字段和属性 ... ... }
8.ORMConfig 类主要用来存储 miniORM.cfg.xml 配置文件中的信息和 Mapper 映射信息,该类内部会使用 Dom4jUtil、AnnotationUtil 工具类去解析数据,源码如下所示:
public class ORMConfig { public static String classpath; //类路径public static File cfgFile; //核心配置文件 public static Map<String, String> propConfig; //核心配置文件数据public static Set<String> mappingSet; //映射配置文件 public static Set<String> entitySet; //实体类 public static List<Mapper> mapperList; //解析出来的 Mapper // 从 classpath 中加载框架的核心配置文件 miniORM.cfg.xml static { classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); if (classpath == null) { classpath = Thread.currentThread().getContextClassLoader().getResource("/").getPath(); } try { classpath = java.net.URLDecoder.decode(classpath, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } cfgFile = new File(classpath + "miniORM.cfg.xml"); if (cfgFile.exists()) { Document document = Dom4jUtil.getXMLByFilePath(cfgFile.getPath()); propConfig = Dom4jUtil.Elements2Map(document, "property", "name"); mappingSet = Dom4jUtil.Elements2Set(document, "mapping", "resource"); entitySet = Dom4jUtil.Elements2Set(document, "entity", "package"); } else { cfgFile = null; System.out.println("未找到核心配置文件 miniORM.cfg.xml"); } } //从 propConfig 获得信息,连接数据库 private Connection getConnection() throws ClassNotFoundException, SQLException { String url = propConfig.get("connection.url"); String driverClass = propConfig.get("connection.driverClass"); String username = propConfig.get("connection.username"); String password = propConfig.get("connection.password"); Class.forName(driverClass); Connection connection = DriverManager.getConnection(url, username, password); connection.setAutoCommit(true); return connection; } //从 mappingSet 中挨个解析 mapper.xml 配置文件,获得实体类和表之间的映射信息 //从 entitySet 中挨个解析实体类中的注解,获得实体类和表之间的映射信息 private void getMapping() throws ClassNotFoundException { mapperList = new ArrayList<>(); for (String xmlPath : mappingSet) { Document document = Dom4jUtil.getXMLByFilePath(classpath + xmlPath); Map<String, String> mapping = Dom4jUtil.Elements2Map(document); String className = Dom4jUtil.getPropValue(document, "class", "name"); String tableName = Dom4jUtil.getPropValue(document, "class", "table"); Map<String, String> id_id = Dom4jUtil.ElementsID2Map(document); Mapper mapper = new Mapper(); mapper.setClassName(className); mapper.setTableName(tableName); mapper.setIdMapper(id_id); mapper.sePropMapping(mapping); mapperList.add(mapper); } for (String packagePath : entitySet) { Set<String> nameSet = AnnotationUtil.getClassNameByPackage(packagePath); for (String name : nameSet) { Class clz = Class.forName(name); String className = AnnotationUtil.getClassName(clz); String tableName = AnnotationUtil.getTableName(clz); Map<String, String> id_id = AnnotationUtil.getIdMapper(clz); Map<String, String> mapping = AnnotationUtil.getPropMapping(clz); Mapper mapper = new Mapper(); mapper.setClassName(className); mapper.setTableName(tableName); mapper.setIdMapper(id_id); mapper.sePropMapping(mapping); mapperList.add(mapper); } } } public ORMSession buildORMSession() throws Exception { //从 propConfig 获得信息,连接数据库 Connection connection = getConnection(); //从 mappingSet 中挨个解析 mapper.xml 配置文件,获得实体类和表之间的映射信息 getMapping(); //创建 ORMSession 对象 return new ORMSession(connection); } }
9.ORMSession 类主要用来从 ORMConfig 和 Mapper 中获取相关数据,然后生成 sql 语句,最后通过对 JDBC 的封装最终实现增删改查功能,源码如下所示:
public class ORMSession { private Connection connection; public ORMSession(Connection conn) { this.connection = conn; } //保存数据 public void save(Object entity) throws Exception { String insertSQL = ""; //1. 从 ORMConfig 中获得保存有映射信息的集合 List<Mapper> mapperList = ORMConfig.mapperList; //2. 遍历集合,从集合中找到和 entity 参数相对应的 mapper 对象 for (Mapper mapper : mapperList) { if (mapper.getClassName().equals(entity.getClass().getName())) { String tableName = mapper.getTableName(); String insertSQL1 = "insert into " + tableName + "( "; String insertSQL2 = " ) values ( "; //3. 得到当前对象所属类中的所有属性 Field[] fields = entity.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); //4. 遍历过程中根据属性得到字段名 String columnName = mapper.getPropMapper().get(field.getName()); //5. 遍历过程中根据属性得到它的值 String columnValue = field.get(entity).toString(); //6. 拼接 sql 语句 insertSQL1 += columnName + ","; insertSQL2 += "'" + columnValue + "',"; } insertSQL = insertSQL1.substring(0, insertSQL1.length() - 1) + insertSQL2.substring(0, insertSQL2.length() - 1) + " )"; break; } } // 把 sql 语句打印到控制台 System.out.println("MiniORM-save: " + insertSQL); //7. 通过 JDBC 发送并执行 sql PreparedStatement statement = connection.prepareStatement(insertSQL); statement.executeUpdate(); statement.close(); } //根据主键进行数据删除 delete from 表名 where 主键 = 值 public void delete(Object entity) throws Exception { String delSQL = "delete from "; //1. 从 ORMConfig 中获得保存有映射信息的集合 List<Mapper> mapperList = ORMConfig.mapperList; //2. 遍历集合,从集合中找到和 entity 参数相对应的 mapper 对象 for (Mapper mapper : mapperList) { if (mapper.getClassName().equals(entity.getClass().getName())) { // 3. 得到我们想要的 mapper 对象,并得到表名String tableName = mapper.getTableName(); delSQL += tableName + " where "; // 4. 得到主键的字段名和属性名 Object[] idProp = mapper.getIdMapper().keySet().toArray(); //idProp[0] Object[] idColumn = mapper.getIdMapper().values().toArray(); //idColumn[0] // 5. 得到主键的值 Field field = entity.getClass().getDeclaredField(idProp[0].toString()); field.setAccessible(true); String idVal = field.get(entity).toString(); // 6. 拼接 sql delSQL += idColumn[0].toString() + " = " + idVal; // 把 sql 语句打印到控制台 System.out.println("MiniORM-delete: " + delSQL); break; } } //7. 通过 JDBC 发送并执行 sql PreparedStatement statement = connection.prepareStatement(delSQL); statement.executeUpdate(); statement.close(); } // 根据主键进行查询 select * from 表名 where 主键字段 = 值 public Object findOne(Class clz, Object id) throws Exception{ String querySQL = "select * from "; //1. 从 ORMConfig 中得到存有映射信息的集合 List<Mapper> mapperList=ORMConfig.mapperList; //2. 遍历集合拿到我们想要的 mapper 对象 for (Mapper mapper : mapperList) { if (mapper.getClassName().equals(clz.getName())) { // 3. 获得表名 String tableName = mapper.getTableName(); //4. 获得主键字段名 Object[] idColumn = mapper.getIdMapper().values().toArray(); //idColumn[0] //5. 拼接 sql querySQL += tableName + " where " + idColumn[0].toString() + " = " + id; break; } } System.out.println("MiniORM-findOne:" +querySQL); //6. 通过 jdbc 发送并执行 sql, 得到结果集 PreparedStatement statement=connection.prepareStatement(querySQL); ResultSet rs=statement.executeQuery(); //7. 封装结果集,返回对象 if(rs.next()){ // 查询到一行数据 // 8.创建一个对象,目前属性的值都是初始值Object obj=clz.newInstance(); // 9. 遍历 mapperList 集合找到我们想要的 mapper 对象 for(Mapper mapper:mapperList){ if (mapper.getClassName().equals(clz.getName())) { //10. 得到存有属性-字段的映射信息 Map<String,String> propMap = mapper.getPropMapper(); //11. 遍历集合分别拿到属性名和字段名Set<String> keySet = propMap.keySet(); for(String prop:keySet){ //prop 就是属性名 String column = propMap.get(prop); //column 就是和属性对应的字段名 Field field = clz.getDeclaredField(prop); field.setAccessible(true); field.set(obj,rs.getObject(column)); } break; } } //12. 释放资源statement.close(); rs.close(); //13. 返回查询出来的对象 return obj; }else { // 没有查到数据 return null; } } //关闭连接,释放资源 public void close() throws Exception{ if(connection!=null){ connection.close(); connection = null; } } }
4.3MiniORM 框架的测试使用
我们自定义的 MiniORM 框架主要用来体现 ORM 思想,并不是为了开发一个成熟的持久层框架出来,因此很多逻辑并不完善,很多情况也未去考虑,请各位理解。接下来我们就测试一下该框架。
1.pom.xml
<groupId>cn.itcast.orm</groupId> <artifactId>TestMiniORM</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>cn.itcast.framework.miniorm</groupId> <artifactId>MiniORM</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.36</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <!--为了编译时能加载包中的 xml 文件--> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <!--为了编译时能加载 resources 中的 xml 文件--> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
我们前面把 MiniORM 框架打成 jar 包并 install 到了本地 Maven 仓库中,因此在使用该框架时需要从本地仓库进行加载。
2.miniORM.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <orm-factory> <!--数据库连接--> <property name="connection.url">jdbc:mysql://localhost:3306/test</property> <property name="connection.driverClass">com.mysql.jdbc.Driver</property> <property name="connection.username">root</property> <property name="connection.password">123</property> <!--采用 xml 配置映射数据--> <mapping resource="cn/itcast/orm/test/entity/Book.mapper.xml"/> <!--采用注解配置映射数据--> <entity package="cn.itcast.orm.test.entity"/> </orm-factory>
这是框架的核心配置文件,我们既采用了 xml 方式配置映射数据,也采用了注解方式在实体
类中配置映射数据,最后可以二选一分别进行功能测试。
3.实体类和映射配置文件
@ORMTable(name = "t_book") public class Book { @ORMId @ORMColumn(name = "bid") private int id; //主键 @ORMColumn(name="bname") private String name; //图书名字 @ORMColumn(name="author") private String author; //图书作者 @ORMColumn(name="price") private double price; //图书价格 ... ... } <?xml version='1.0' encoding='UTF-8'?> <!--实体类和表之间的映射关系配置--> <orm-mapping> <class name="cn.itcast.orm.test.entity.Book" table="t_book"> <id name="id" column="bid"/> <property name="name" column="bname"/> <property name="author" column="author"/> <property name="price" column="price"/> </class> </orm-mapping>
注意:对于同一个表或实体类,不需要既进行 xml 配置,又进行注解配置,二选一即可,这
里同时进行配置只是为了测试方便。
测试类
public class BookDao { private ORMConfig config; @Before public void init() { config = new ORMConfig(); } @Test public void testSave() throws Exception { ORMSession session = config.buildORMSession(); Book book = new Book(); book.setId(1); book.setName("降龙十八掌"); book.setAuthor("不知道"); book.setPrice(9.9); session.save(book); session.close(); } @Test public void testDelete() throws Exception { ORMSession session = config.buildORMSession(); Book book = new Book(); book.setId(1); session.delete(book); session.close(); } @Test public void testFindOne() throws Exception { ORMSession session = config.buildORMSession(); Book book = (Book) session.findOne(Book.class, 1); System.out.println(book); session.close(); }
?我们调用 ORMSession 类的 save 方法完成了数据保存功能,由 MiniORM 框架生成 sql语句,运行效果如下图所示:
?我们调用 ORMSession 类的 findOne 方法完成了数据查询功能,由 MiniORM 框架生成sql语句,运行效果如下图所示:
?我们调用 ORMSession 类的 delete 方法完成了数据删除功能,由 MiniORM 框架生成 sql语句,运行效果如下图所示:
相关推荐
- 迈向群体智能 | 智源发布首个跨本体具身大小脑协作框架
-
允中发自凹非寺量子位|公众号QbitAI3月29日,智源研究院在2025中关村论坛“未来人工智能先锋论坛”上发布首个跨本体具身大小脑协作框架RoboOS与开源具身大脑RoboBrain,可实...
- 大模型对接微信个人号,极空间部署AstrBot机器人,万事不求百度
-
「亲爱的粉丝朋友们好啊!今天熊猫又来介绍好玩有趣的Docker项目了,喜欢的记得点个关注哦!」引言前两天熊猫发过一篇关于如何在极空间部署AstrBot并对接QQ消息平台的文章,不过其实QQ现在已经很少...
- Seata,让分布式事务不再是难题!实战分享带你领略Seata的魅力!
-
终身学习、乐于分享、共同成长!前言Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的...
- 常见分布式事务解决方案(分布式事务解决的问题)
-
1.两阶段提交(2PC)原理:分为准备阶段(协调者询问参与者是否可提交)和提交阶段(协调者根据参与者反馈决定提交或回滚)。优点:强一致性,适用于数据库层(如XA协议)。缺点:同步阻塞:所有参与者阻塞...
- 分布式事务:从崩溃到高可用,程序员必须掌握的实战方案!
-
“支付成功,但订单状态未更新!”、“库存扣减后,交易却回滚了!”——如果你在分布式系统中踩过这些“天坑”,这篇文章就是你的救命稻草!本文将手把手拆解分布式事务的核心痛点和6大主流解决方案,用代码实战+...
- 谈谈对分布式事务的一点理解和解决方案
-
分布式事务首先,做系统拆分的时候几乎都会遇到分布式事务的问题,一个仿真的案例如下:项目初期,由于用户体量不大,订单模块和钱包模块共库共应用(大war包时代),模块调用可以简化为本地事务操作,这样做只要...
- 一篇教你通过Seata解决分布式事务问题
-
1 Seata介绍Seata是由阿里中间件团队发起的开源分布式事务框架项目,依赖支持本地ACID事务的关系型数据库,可以高效并且对业务0侵入的方式解决微服务场景下面临的分布式事务问题,目前提供AT...
- Seata分布式事务详解(原理流程及4种模式)
-
Seata分布式事务是SpringCloudAlibaba的核心组件,也是构建分布式的基石,下面我就全面来详解Seata@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合...
- 分布式事务最终一致性解决方案有哪些?MQ、TCC、saga如何实现?
-
JTA方案适用于单体架构多数据源时实现分布式事务,但对于微服务间的分布式事务就无能为力了,我们需要使用其他的方案实现分布式事务。1、本地消息表本地消息表的核心思想是将分布式事务拆分成本地事务进行处理...
- 彻底掌握分布式事务2PC、3PC模型(分布式事务视频教程)
-
原文:https://mp.weixin.qq.com/s/_zhntxv07GEz9ktAKuj70Q作者:马龙台工作中使用最多的是本地事务,但是在对单一项目拆分为SOA、微服务之后,就会牵扯出分...
- Seata分布式事务框架关于Annotation的SAGA模式分析
-
SAGAAnnotation是ApacheSeata版本2.3.0中引入的功能,它提供了一种使用Java注解而不是传统的JSON配置或编程API来实现SAGA事务模式的声明...
- 分布式事务,原理简单,写起来全是坑
-
今天我们就一起来看下另一种模式,XA模式!其实我觉得seata中的四种不同的分布式事务模式,学完AT、TCC以及XA就够了,Saga不好玩,而且长事务本身就有很多问题,也不推荐使用。S...
- 内存空间节约利器redis的bitmap(位图)应用场景有哪些你知道吗
-
在前面我们分享过一次Redis常用数据结构和使用场景,文章对Redis基本使用做了一个简单的API说明,但是对于其中String类型中的bitmap(位图)我们需要重点说明一下,因为他的作用真的不容忽...
- 分布式事务原理详解(图文全面总结)
-
分布式事务是非常核心的分布式系统,也是大厂经常考察对象,下面我就重点详解分布式事务及原理实现@mikechen本文作者:陈睿|mikechen文章来源:mikechen.cc分布式事务分布式事务指的是...
- 大家平时天天说的分布式系统到底是什么东西?
-
目录从单块系统说起团队越来越大,业务越来越复杂分布式出现:庞大系统分而治之分布式系统所带来的技术问题一句话总结:什么是分布式系统设计和开发经验补充说明:中间件系统及大数据系统前言现在有很多Java技术...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- express框架 (43)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (52)
- java框架spring (43)
- grpc框架 (55)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)