SpringBoot + MyBatis + MySQL okuma-yazma ayrımı (örnek)

Yazar: oğlunuzu çılgına çevirin, ihlal varsa, lütfen sil ile iletişime geçin, teşekkürler. cnblogs.com/cjsblog/p/9712457.html

1. Giriş

Okuma-yazma ayrımı için yapmamız gereken şey, bir SQL parçası için hangi veritabanının yürütüleceğini seçmektir Veritabanını kimin seçeceğine gelince, ikiden fazlası yoktur.Ya ara yazılım bunu bizim için yapar veya program kendi başına yapar. Bu nedenle, genel olarak konuşmak gerekirse, okuma ve yazmanın birbirinden ayrılmasını sağlamanın iki yolu vardır. Birincisi ara katman yazılımına güvenmektir (örneğin: MyCat), bu da uygulamanın ara katman yazılımına bağlı olduğu ve ara yazılımın SQL ayırma yapmamıza yardımcı olduğu anlamına gelir; ikincisi ise ayırmayı kendi kendine yapan uygulamadır. Burada, esas olarak Spring ve AOP tarafından sağlanan yönlendirme veri kaynağını kullanarak, bunu kendimiz yapacak programı seçiyoruz.

Bununla birlikte, uygulama düzeyinde okuma ve yazma ayrımının en büyük zayıflığı (eksikliği), veri kaynağı yapılandırmasının yapılandırmada yazılması nedeniyle veritabanı düğümünün dinamik olarak eklenememesi ve yeni veritabanı, değiştirilmesi gereken yeni bir veri kaynağının eklenmesi anlamına gelmesidir. Uygulamayı yapılandırın ve yeniden başlatın. Elbette avantajı, nispeten basit olmasıdır.

2. AbstractRoutingDataSource

Belirli bir arama anahtarına göre belirli bir veri kaynağına yönlendirin. Bir dizi hedef veri kaynağını dahili olarak tutar ve yönlendirme anahtarları ile hedef veri kaynakları arasında bir eşleme yapar ve anahtarlara dayalı veri kaynaklarını bulmak için yöntemler sağlar.

3. Pratik yapın

Yapılandırma için lütfen şunlara bakın:

https://www.cnblogs.com/cjsblog/p/9706370.html

3.1. Maven bağımlılığı

< ? xml version = "1.0" encoding = "UTF-8"? > < proje xmlns = " xmlns: xsi = " xsi: schemaLocation = " > < modelVersion > 4.0.0 < / modelVersion > < Grup kimliği > com.cjs.example < /Grup kimliği > < artifactId > cjs-datasource-demo < / artifactId > < versiyon > 0.0.1-SNAPSHOT < / version > < ambalaj > kavanoz < / paketleme > < isim > cjs-datasource-demo < / isim > < açıklama > < /açıklama > < ebeveyn > < Grup kimliği > org.springframework.boot < /Grup kimliği > < artifactId > Spring-boot-starter-ebeveyn < / artifactId > < versiyon > 2.0.5. YAYIN < / version > < göreceli yol/ > < ! - depodan ebeveyn araması - > < / ebeveyn > < özellikleri > < project.build.sourceEncoding > UTF-8 < /project.build.sourceEncoding > < project.reporting.outputEncoding > UTF-8 < /project.reporting.outputEncoding > < java.version > 1.8 < /java.version > < /özellikleri > < bağımlılıklar > < bağımlılık > < Grup kimliği > org.springframework.boot < /Grup kimliği > < artifactId > Spring-boot-starter-aop < / artifactId > < /bağımlılık > < bağımlılık > < Grup kimliği > org.springframework.boot < /Grup kimliği > < artifactId > Spring-boot-starter-jdbc < / artifactId > < /bağımlılık > < bağımlılık > < Grup kimliği > org.springframework.boot < /Grup kimliği > < artifactId > Spring-boot-starter-web < / artifactId > < /bağımlılık > < bağımlılık > < Grup kimliği > org.mybatis.spring.boot < /Grup kimliği > < artifactId > mybatis-spring-boot-starter < / artifactId > < versiyon > 1.3.2 < / version > < /bağımlılık > < bağımlılık > < Grup kimliği > org.apache.commons < /Grup kimliği > < artifactId > commons-lang3 < / artifactId > < versiyon > 3.8 < / version > < /bağımlılık > < bağımlılık > < Grup kimliği > mysql < /Grup kimliği > < artifactId > mysql-bağlayıcı-java < / artifactId > < dürbün > Çalışma süresi < /dürbün > < /bağımlılık > < bağımlılık > < Grup kimliği > org.springframework.boot < /Grup kimliği > < artifactId > yay önyükleme başlangıç testi < / artifactId > < dürbün > Ölçek < /dürbün > < /bağımlılık > < / bağımlılıklar > < inşa etmek > < eklentiler > < Eklenti > < Grup kimliği > org.springframework.boot < /Grup kimliği > < artifactId > Spring-boot-maven-eklentisi < / artifactId > < /Eklenti > < ! - < Eklenti > < Grup kimliği > org.mybatis.generator < /Grup kimliği > < artifactId > mybatis-generator-maven-eklentisi < / artifactId > < versiyon > 1.3.5 < / version > < bağımlılıklar > < bağımlılık > < Grup kimliği > mysql < /Grup kimliği > < artifactId > mysql-bağlayıcı-java < / artifactId > < versiyon > 5.1.46 < / version > < /bağımlılık > < / bağımlılıklar > < konfigürasyon > < configurationFile > $ {basedir} /src/main/resources/myBatisGeneratorConfig.xml < / configurationFile > < üzerine yazmak > doğru < / üzerine yaz > < / configuration > < infazlar > < icra > < İD > MyBatis Yapıları Oluşturun < /İD > < hedefler > < hedef > oluşturmak < /hedef > < /hedefler > < / yürütme > < / infazlar > < /Eklenti > - > < / plugins > < /inşa etmek > < / proje >

3.2. Veri kaynağı yapılandırması

application.yml

bahar: veri kaynağı: usta: jdbc-url: jdbc: mysql: //192.168.102.31: 3306 / test kullanıcı adı: kök şifre: 123456 sürücü sınıfı adı: com.mysql.jdbc.Driver köle1: jdbc-url: jdbc: mysql: //192.168.102.56: 3306 / test username: pig # Salt okunur hesap şifre: 123456 sürücü sınıfı adı: com.mysql.jdbc.Driver köle2: jdbc-url: jdbc: mysql: //192.168.102.36: 3306 / test username: pig # Salt okunur hesap şifre: 123456 sürücü sınıfı adı: com.mysql.jdbc.Driver

Çoklu veri kaynağı yapılandırması

paket com.cjs.example.config; import com.cjs.example.bean.MyRoutingDataSource; import com.cjs.example.enums.DBTypeEnum; import org.springframework.beans.factory.annotation.Qualifier; org.springframework.boot.context.properties.ConfigurationProperties dosyasını içe aktar; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; org.springframework.context.annotation.Configuration dosyasını içe aktarın; javax.sql.DataSource'u içe aktar; java.util.HashMap'i içe aktar; java.util.Map içe aktarın; / ** * Veri kaynağı yapılandırması için, SpringBoot resmi belgesinin Bölüm 79 "Veri Erişimi" ne bakın * 79. Veri Erişimi * 79.1 Özel Veri Kaynağını Yapılandırma * 79.2 İki Veri Kaynağını Yapılandırın * / @Yapılandırma public class DataSourceConfig { @Fasulye @ConfigurationProperties ("spring.datasource.master") public DataSource masterDataSource () { return DataSourceBuilder.create (). build (); } @Fasulye @ConfigurationProperties ("spring.datasource.slave1") public DataSource slave1DataSource () { return DataSourceBuilder.create (). build (); } @Fasulye @ConfigurationProperties ("spring.datasource.slave2") public DataSource slave2DataSource () { return DataSourceBuilder.create (). build (); } @Fasulye public DataSource myRoutingDataSource (@Qualifier ("masterDataSource") DataSource masterDataSource, @Qualifier ("slave1DataSource") DataSource slave1DataSource, @Qualifier ("slave2DataSource") DataSource slave2DataSource) { Harita < Nesne, Nesne > targetDataSources = yeni HashMap < > (); targetDataSources.put (DBTypeEnum.MASTER, masterDataSource); targetDataSources.put (DBTypeEnum.SLAVE1, slave1DataSource); targetDataSources.put (DBTypeEnum.SLAVE2, slave2DataSource); MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource (); myRoutingDataSource.setDefaultTargetDataSource (masterDataSource); myRoutingDataSource.setTargetDataSources (targetDataSources); myRoutingDataSource döndür; } }

Burada 4 veri kaynağı, 1 ana, 2 bağımlı ve 1 yönlendirme veri kaynağı yapılandırdık. İlk 3 veri kaynağı, dördüncü veri kaynağını oluşturmak için kullanılır ve gelecekte yalnızca son yönlendirme veri kaynağını kullanacağız.

MyBatis yapılandırması

paket com.cjs.example.config; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.context.annotation.Bean; org.springframework.context.annotation.Configuration dosyasını içe aktarın; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.annotation.Resource; javax.sql.DataSource'u içe aktar; @EnableTransactionManagement @Yapılandırma public class MyBatisConfig { @Resource (name = "myRoutingDataSource") özel DataSource myRoutingDataSource; @Fasulye public SqlSessionFactory sqlSessionFactory (), Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean (); sqlSessionFactoryBean.setDataSource (myRoutingDataSource); sqlSessionFactoryBean.setMapperLocations (yeni PathMatchingResourcePatternResolver (). getResources ("classpath: mapper / *. xml")); dönüş sqlSessionFactoryBean.getObject (); } @Fasulye public PlatformTransactionManager platformTransactionManager () { yeni DataSourceTransactionManager (myRoutingDataSource) döndür; } }

Spring konteynerinde artık 4 veri kaynağı olduğundan, işlem yöneticisi ve MyBatis için manuel olarak net bir veri kaynağı belirlememiz gerekiyor.

3.3. Yönlendirme anahtarını ayarlayın / veri kaynağını bulun

Hedef veri kaynağı bildiğimiz ilk 3 kaynaktır, ancak onu kullanırken veri kaynağı nasıl bulunur?

İlk olarak, bu üç veri kaynağını temsil edecek bir numaralandırma tanımlıyoruz

paket com.cjs.example.enums; public enum DBTypeEnum { MASTER, SLAVE1, SLAVE2; }

Ardından, veri kaynağını ThreadLocal aracılığıyla her iş parçacığı bağlamına ayarlayın

paket com.cjs.example.bean; import com.cjs.example.enums.DBTypeEnum; import java.util.concurrent.atomic.AtomicInteger; public class DBContextHolder { özel statik final ThreadLocal < DBTypeEnum > contextHolder = yeni ThreadLocal < > (); özel statik son AtomicInteger sayacı = new AtomicInteger (-1); public static void set (DBTypeEnum dbType) { contextHolder.set (dbType); } public static DBTypeEnum get () { return contextHolder.get (); } public static void master () { set (DBTypeEnum.MASTER); System.out.println ("Ana sayfaya geç"); } public static void slave () { // anket int index = counter.getAndIncrement ()% 2; eğer (counter.get () > 9999) { counter.set (-1); } eğer (indeks == 0) { set (DBTypeEnum.SLAVE1); System.out.println ("Slave1'e geç"); }Başka { set (DBTypeEnum.SLAVE2); System.out.println ("Slave2'ye geç"); } } }

Yönlendirme anahtarını alın

paket com.cjs.example.bean; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.lang.Nullable; public class MyRoutingDataSource, AbstractRoutingDataSource { @Nullable @Override korumalı Nesne determCurrentLookupKey () { DBContextHolder.get () döndür; } }

Yönlendirme anahtarını ayarlayın

Varsayılan olarak, tüm sorgular bağımlı veritabanına gider ve ekle / değiştir / sil ana veritabanına gider. İşlem türünü yöntem adına (CRUD) göre ayırıyoruz

paket com.cjs.example.aop; import com.cjs.example.bean.DBContextHolder; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Görünüş @Bileşen public class DataSourceAop { @Pointcut ("! @ Annotation (com.cjs.example.annotation.Master)" + "(yürütme (* com.cjs.example.service .. *. seçin * (..))" + "|| yürütme (* com.cjs.example.service .. *. get * (..)))") public void readPointcut () { } @Pointcut ("@ annotation (com.cjs.example.annotation.Master)" + "|| yürütme (* com.cjs.example.service .. *. insert * (..))" + "|| yürütme (* com.cjs.example.service .. *. ekle * (..))" + "|| yürütme (* com.cjs.example.service .. *. güncelleme * (..))" + "|| yürütme (* com.cjs.example.service .. *. düzenle * (..))" + "|| yürütme (* com.cjs.example.service .. *. sil * (..))" + "|| yürütme (* com.cjs.example.service .. *. remove * (..))") public void writePointcut () { } @Before ("readPointcut ()") public void read () { DBContextHolder.slave (); } @Before ("writePointcut ()") public void write () { DBContextHolder.master (); } / ** * Başka bir yazma yolu: if ... else ... hangilerinin veritabanından okunması gerektiğini belirlemek ve geri kalanı ana veritabanına gitmek için * / // @Before ("yürütme (* com.cjs.example.service.impl. *. * (..))") // öncesinde public void (JoinPoint jp) { // String methodName = jp.getSignature (). GetName (); // // if (StringUtils.startsWithAny (methodName, "get", "select", "find")) { // DBContextHolder.slave (); // }Başka { // DBContextHolder.master (); //} //} }

Genel durumlar ve özel durumlar vardır.Bazı durumlarda, ana kitaplığın okunmasını zorlamamız gerekir.Bu durumda, bir birincil anahtar tanımlıyoruz ve ana kitaplığı işaretlemek için açıklamayı kullanıyoruz.

paket com.cjs.example.annotation; public @interface Master { }

Örneğin, bir masa üyemiz olduğunu varsayalım

paket com.cjs.example.service.impl; ithal com.cjs.example.annotation.Master; import com.cjs.example.entity.Member; import com.cjs.example.entity.MemberExample; import com.cjs.example.mapper.MemberMapper; import com.cjs.example.service.MemberService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Hizmet public class MemberServiceImpl MemberService'i uygular { @Autowired özel MemberMapper memberMapper; @Transactional @Override public int insert (Üye üye) { üyeMapper.insert (üye) döndür; } @Usta @Override public int save (Üye üye) { üyeMapper.insert (üye) döndür; } @Override genel Liste < Üye > hepsini seç() { return memberMapper.selectByExample (new MemberExample ()); } @Usta @Override public String getToken (String appId) { // Bazı okuma işlemleri ana veritabanını okumalıdır // Örneğin, WeChat erişim belirtecini alın, çünkü ana-bağımlı senkronizasyonu yoğun dönemlerde gecikebilir // Bu durumda ana veriden okunmaya zorlanmalıdır boş döndür; } }

4. Test Etme

paket com.cjs.example; import com.cjs.example.entity.Member; import com.cjs.example.service.MemberService; org.junit.Test'i içe aktar; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith (SpringRunner.class) @Hayalhanemersin public class CjsDatasourceDemoApplicationTests { @Autowired özel MemberService memberService; @Ölçek public void testWrite () { Üye üye = yeni Üye (); üye.setName ("zhangsan"); memberService.insert (üye); } @Ölçek public void testRead () { for (int i = 0; i < 4; i ++) { memberService.selectAll (); } } @Ölçek public void testSave () { Üye üye = yeni Üye (); üye.setName ("wangwu"); memberService.save (üye); } @Ölçek public void testReadFromMaster () { memberService.getToken ("1234"); }

Konsolu görüntüle

5. Mühendislik yapısı

2018 Display ZDC: E-spor ekran fiyat savaşı kaçınılmaz
önceki
"Şehir Modeli" 2018 yeni kitap tanıtım töreni ve şehir modeli ödül törenini gerçekleştirdi
Sonraki
Mavi gökyüzünün altında WuhanQingshan Yangtze Nehri Köprüsü'nün çizimi
Yeni yardım fonu anlaşması, gençlerin zarar görmesi mümkün değil
Alipay, mobil ödeme alanında daha gelişmiş olan netizenlere yanıt verdi.
Bahar 2018 Çin x86 Sunucu Pazarı Araştırma Raporunu Kucaklayın
Etkinlik Yetiştirme "Sonbahar tadı" ile geleneksel bir uğurlu tütsü yaptı
Lenovo kurtarıcı Y9000K neden 10 dakika içinde tükeniyor?
Programcı, şirketin temizlik teyzesine sormadığından ve bir çalışanın her gün "görev başında" olduğundan şikayet ediyor
İtalyan medyası, İtalyan yaşam tarzını değiştirdiği için ortak bisikletlerimizi övdü
Zibo: Hükümet, Yılbaşı ürünlerini hazırlamak için bir platform kuruyor
Kağıtlar için çağrı Bir fincan parlak ay girişi, Sonbahar Ortası Festivali'nin tadını biliyor musunuz?
SpongeBob SquarePants'ın yazarı öldü, ancak İnternet için bir hazine bıraktı
Kadın netizenler, her gün motive olmayan programcı erkek arkadaşlarından şikayet ediyor ve birlikte üç günlüğüne bölünüyorlar!
To Top