diff --git a/README.md b/README.md index e5497df..721945a 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,5 @@ 查看配置文件 -### 2. \ No newline at end of file +### 2. 事务支持 + https://segmentfault.com/a/1190000023379017 \ No newline at end of file diff --git a/pom.xml b/pom.xml index b013fb1..cce0a01 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ 8 8 2.3.2.RELEASE + 4.1.1 pom @@ -31,14 +32,28 @@ org.apache.shardingsphere sharding-jdbc-spring-boot-starter - 4.1.1 + ${apache.shardingsphere.version} org.apache.shardingsphere sharding-jdbc-spring-namespace - 4.1.1 + ${apache.shardingsphere.version} + + + + + org.apache.shardingsphere + sharding-transaction-xa-core + ${apache.shardingsphere.version} + + + + + org.apache.shardingsphere + sharding-transaction-base-seata-at + ${apache.shardingsphere.version} @@ -87,6 +102,7 @@ druid 1.2.4 + \ No newline at end of file diff --git a/sharding-multiple-data-sources/pom.xml b/sharding-multiple-data-sources/pom.xml index 9895adc..0a9eddb 100644 --- a/sharding-multiple-data-sources/pom.xml +++ b/sharding-multiple-data-sources/pom.xml @@ -34,6 +34,11 @@ sharding-jdbc-spring-namespace + + org.apache.shardingsphere + sharding-transaction-xa-core + + org.springframework.boot spring-boot-starter-data-jpa diff --git a/sharding-multiple-data-sources/sql/t_order_0.sql b/sharding-multiple-data-sources/sql/t_order_0.sql new file mode 100644 index 0000000..b589268 --- /dev/null +++ b/sharding-multiple-data-sources/sql/t_order_0.sql @@ -0,0 +1,31 @@ +/* + ps: 注意配置了多少分表就创建多少张 + + Source Server : 本地环境mysql + Source Server Type : MySQL + Source Server Version : 80026 + Source Host : localhost:3306 + Source Schema : shard-1 + + Target Server Type : MySQL + Target Server Version : 80026 + File Encoding : 65001 + + Date: 24/10/2021 01:42:50 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for t_order_0 +-- ---------------------------- +DROP TABLE IF EXISTS `t_order`; +CREATE TABLE `t_order_0` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `order_name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java b/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java index 45cbfd8..6a71ca4 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/ShardingMultipleDataSourceApplication.java @@ -2,6 +2,10 @@ package com.baiye; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; +import org.springframework.transaction.annotation.EnableTransactionManagement; /** * @author q @@ -12,4 +16,19 @@ public class ShardingMultipleDataSourceApplication { public static void main(String[] args) { SpringApplication.run(ShardingMultipleDataSourceApplication.class, args); } + + + /** + * 按照日志要求将 open-in-view=false。再次启动,如果在实体类中外键字段使用了懒加载模式,在视图层中调用数据时,则会出现 no session 异常。 + * + * 解决方法:手动注册OpenEntityManagerInViewFilter过滤器,改变session的生命周期,当web请求关闭时才结束session。 + */ + @Bean + public FilterRegistrationBean openEntityManagerInViewFilterFilterRegistrationBean(){ + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + OpenEntityManagerInViewFilter filter = new OpenEntityManagerInViewFilter(); + filterRegistrationBean.setFilter(filter); + filterRegistrationBean.setOrder(5); + return filterRegistrationBean; + } } diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/config/TransactionConfiguration.java b/sharding-multiple-data-sources/src/main/java/com/baiye/config/TransactionConfiguration.java new file mode 100644 index 0000000..64e6747 --- /dev/null +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/config/TransactionConfiguration.java @@ -0,0 +1,29 @@ +package com.baiye.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; + + +/** + * shardingJDBC - 事务支持 + */ +@Configuration +@EnableTransactionManagement +public class TransactionConfiguration { + + @Bean(name = "transactionManager") + public PlatformTransactionManager txManager(final DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean + public JdbcTemplate jdbcTemplate(final DataSource dataSource) { + return new JdbcTemplate(dataSource); + } +} diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/OrderRepository.java b/sharding-multiple-data-sources/src/main/java/com/baiye/dao/OrderRepository.java index 94827f7..d7869ce 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/dao/OrderRepository.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/dao/OrderRepository.java @@ -10,7 +10,7 @@ import org.springframework.transaction.annotation.Transactional; /** * @author q */ -public interface OrderRepository extends JpaRepository { +public interface OrderRepository extends JpaRepository { @Query(value = "insert into order (id,ordername) values (?1,?2)", nativeQuery = true) @Modifying diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/domain/Order.java b/sharding-multiple-data-sources/src/main/java/com/baiye/domain/Order.java index 532612d..ef530a3 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/domain/Order.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/domain/Order.java @@ -7,14 +7,16 @@ import java.io.Serializable; @Entity @Data -@Table(name = "order") +@Table(name = "t_order") public class Order implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Integer id; + private Long id; - private String userid; + @Column(name = "user_id") + private Long userId; - private String ordername; + @Column(name = "order_name") + private String orderName; } diff --git a/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java b/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java index 317bf10..9cc69c7 100644 --- a/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java +++ b/sharding-multiple-data-sources/src/main/java/com/baiye/service/ShardService.java @@ -3,11 +3,14 @@ package com.baiye.service; import com.baiye.dao.OrderRepository; import com.baiye.domain.Order; -import com.baiye.domain.User; +import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType; +import org.apache.shardingsphere.transaction.core.TransactionType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; /** * @author q @@ -21,35 +24,45 @@ public class ShardService { /** * 增 */ - public Order insertOne(Order order){ + public Order insertOne(Order order) { return orderRepository.save(order); } /** * 批量增加 */ - public List batchInsert(List orders){ + public List batchInsert(List orders) { return orderRepository.saveAll(orders); } + public Order queryOne(Long id) { + Optional optional = orderRepository.findById(id); + return optional.orElse(null); + } + + /** - * 查 + * 批量查 */ - public List queryByCondition(){ - return orderRepository.findAll(); + public List queryByCondition(List ids) { + return orderRepository.findAllById(ids); } /** * 修改 + *

+ * 事务支持 支持TransactionType.LOCAL, TransactionType.XA(已经配置), TransactionType.BASE */ - public Order updateByCondition(Order order){ + @Transactional(value = "transactionManager") + @ShardingTransactionType(TransactionType.XA) + public Order updateByCondition(Order order) { return orderRepository.save(order); } /** * 删除 */ - public void deleterByCondition(Order order){ + public void deleterByCondition(Order order) { orderRepository.delete(order); } diff --git a/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties b/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties index be54cab..0a8cd63 100644 --- a/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties +++ b/sharding-multiple-data-sources/src/main/resources/application-sharddb.properties @@ -1,22 +1,23 @@ spring.shardingsphere.datasource.names=ds0,ds1 spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource -spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver -spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost:3306/shard-3 +spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.ds0.url=jdbc:mysql://127.0.0.1:3306/shard-1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true spring.shardingsphere.datasource.ds0.username=root spring.shardingsphere.datasource.ds0.password=root spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource -spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver -spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/shard-4 +spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.ds1.url=jdbc:mysql://127.0.0.1:3306/shard-2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useTimezone=true spring.shardingsphere.datasource.ds1.username=root spring.shardingsphere.datasource.ds1.password=root -spring.shardingsphere.sharding.tables.order.actual-data-nodes=ds$->{0..1}.order$->{0..1} -spring.shardingsphere.sharding.tables.order.table-strategy.inline.sharding-column=id -spring.shardingsphere.sharding.tables.order.table-strategy.inline.algorithm-expression=id$->{id % 2} -spring.shardingsphere.sharding.tables.order.key-generator.column=userid -spring.shardingsphere.sharding.tables.order.key-generator.type=SNOWFLAKE - spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=id -spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{id % 2} \ No newline at end of file +spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{id % 2} + +spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds$->{0..1}.t_order_$->{0..1} +spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=user_id +spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{user_id % 2} +spring.shardingsphere.sharding.tables.t_order.key-generator.column=id +spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE + diff --git a/sharding-multiple-data-sources/src/main/resources/application.yml b/sharding-multiple-data-sources/src/main/resources/application.yml index b1ee1e5..99243eb 100644 --- a/sharding-multiple-data-sources/src/main/resources/application.yml +++ b/sharding-multiple-data-sources/src/main/resources/application.yml @@ -9,4 +9,6 @@ spring: properties: hibernate: show_sql: true - + database: mysql + main: + allow-bean-definition-overriding: true diff --git a/sharding-multiple-data-sources/src/test/java/com/baiye/service/ShardServiceTest.java b/sharding-multiple-data-sources/src/test/java/com/baiye/service/ShardServiceTest.java index ca75e9a..7dc6caf 100644 --- a/sharding-multiple-data-sources/src/test/java/com/baiye/service/ShardServiceTest.java +++ b/sharding-multiple-data-sources/src/test/java/com/baiye/service/ShardServiceTest.java @@ -4,13 +4,25 @@ package com.baiye.service; import com.baiye.ShardingMultipleDataSourceApplication; import com.baiye.dao.OrderRepository; import com.baiye.domain.Order; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCallback; import org.springframework.test.context.junit4.SpringRunner; +import java.util.ArrayList; +import java.util.List; + +/** + * 测试总结: + * + * 目前自己测试: + * - 增查时候使用JPA可以满足 + * - 在删除和修改时候使用原生 JdbcTemplate 能更好满足需求 + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = ShardingMultipleDataSourceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class ShardServiceTest { @@ -28,30 +40,90 @@ public class ShardServiceTest { @Test public void insertOne() { Order order = new Order(); - order.setOrdername("111"); + order.setOrderName("111"); + order.setUserId(1L); Order order1 = shardService.insertOne(order); System.out.println("order1 = " + order1); } @Test public void batchInsert() { - for (int i = 1; i < 1000; i++) { + List orders = new ArrayList<>(); + for (long i = 1; i < 1000; i++) { Order order = new Order(); -// order.setUserid(i); - order.setOrdername("testOrder" + i); + order.setUserId(i); + order.setOrderName("testOrder" + i); + orders.add(order); } + List orders1 = shardService.batchInsert(orders); + System.out.println("orders1.size() = " + orders1.size()); + } + + @Test + public void queryOne() { + Order order = shardService.queryOne(658828065589166080L); + System.out.println("order = " + order); + } + + @Test + public void queryByIds() { + List ids = new ArrayList<>(); + + ids.add(658828067556294656L); // 分表1 + ids.add(658828070718799872L); + ids.add(658828067615014913L); + ids.add(658828066444804097L); + List orders = shardService.queryByCondition(ids); + System.out.println("orders = " + orders); } @Test - public void queryByCondition() { + public void updateByJDBC() { + + jdbcTemplate.execute("UPDATE t_order SET order_name = ? WHERE id = ?", + (PreparedStatementCallback) preparedStatement -> { + preparedStatement.setObject(1, "test"); + preparedStatement.setObject(2, 1L); + return preparedStatement.executeUpdate(); + }); +// Order order = new Order(); +// order.setUserId(1L); +// order.setOrderName("test"); +// Order order1 = shardService.updateByCondition(order); +// System.out.println("order1 = " + order1); + + + Order order2 = shardService.queryOne(658828065589166080L); + System.out.println("order2 = " + order2); } + /** + * fixme 有问题,暂时不做使用 + */ @Test - public void updateByCondition() { + @Ignore + public void updateByJPA() { + Order order = new Order(); + order.setUserId(2L); + order.setOrderName("test"); + Order order1 = shardService.updateByCondition(order); + System.out.println("order1 = " + order1); + + Order order2 = shardService.queryOne(658828066071511041L); + System.out.println("order2 = " + order2); } @Test public void deleterByCondition() { + + jdbcTemplate.execute("DELETE FROM t_order WHERE id = ?", + (PreparedStatementCallback) preparedStatement -> { + preparedStatement.setObject(1, 658828067426271232L); + return preparedStatement.executeUpdate(); + }); + + Order order2 = shardService.queryOne(658828067426271232L); + System.out.println("order2 = " + order2); } } \ No newline at end of file