Mybatis攔截器實(shí)現(xiàn)讀寫分離的思路和實(shí)踐
說到這里,我們可以再思考一個(gè)問題,一般數(shù)據(jù)庫(kù)都是主從,也就是很多都是一主多從,對(duì)應(yīng)的就是一寫多讀,意思是寫的時(shí)候?qū)懙街鲙?kù),讀的時(shí)候可以從從庫(kù)的任意中讀取。因此我們的插件要有寫庫(kù)的數(shù)據(jù)源已經(jīng)多個(gè)讀庫(kù)的數(shù)據(jù)源。
上邊說了那么多,如果沒有讀寫識(shí)別的信號(hào),那說的再多也沒有價(jià)值。這塊我們就需要解析SQL或者解析方法上邊的特定注解了。前者為一般模式,后者是靈活配置。當(dāng)然這塊要注意的就是事務(wù)了,事務(wù)肯定要操作單庫(kù),也必然是主庫(kù),道理說了挺多哈。我們?cè)囍芯恳幌略趺醋霭伞?/span>
1.首先就是Mybatis插件了,記得之前我們說mybatis有4個(gè)階段(Executor、ParameterHandler、ResultSetHandler 以及 StatementHandler),每個(gè)階段的各個(gè)方法都可以被攔截,當(dāng)然這塊攔截器的攔截原理責(zé)任鏈模式,過程還是比較難的。然后通過jdk代理的方式植入到mybatis執(zhí)行過程中。這塊的筆記已經(jīng)忘的差不多了。再此貼個(gè)筆記。
Mybatis學(xué)習(xí)筆記(三)- Mybatis插件原理
Mybatis學(xué)習(xí)筆記(二)- Sql的執(zhí)行過程


@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class,Integer.class})})public class MybatisLanjieqi implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();System.out.println(statementHandler.toString());return invocation.proceed();}@Overridepublic Object plugin(Object target) {System.out.println("enter the plugin");if (target instanceof StatementHandler) {return Plugin.wrap(target, this);} else {return target;}}}

考慮到我們要在代碼中靈活決定采用那種類型的數(shù)據(jù)源,因此我們需要需要將現(xiàn)場(chǎng)的一些東西傳過來,比如調(diào)用類的信息。當(dāng)然還有sql的類型什么的。這塊我們debug一下??纯次覀兊腟tatementHandler中有什么值。


public class MyDataSource extends DruidDataSource {private static DruidDataSource write;private static Listreader;//模擬多庫(kù)初始化....public static DruidDataSource getDruidDataSource(String url,String userName,String password) throws SQLException {DruidDataSource ds = new DruidDataSource();ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);try {ds.setFilters("stat,mergeStat,slf4j");} catch (Exception var18) {}ds.setMaxActive(50);ds.setInitialSize(1);ds.setMinIdle(1);ds.setMaxWait(60000);ds.setTimeBetweenEvictionRunsMillis(120000);ds.setMinEvictableIdleTimeMillis(300000);ds.setValidationQuery("SELECT 'x'");ds.setPoolPreparedStatements(true);ds.setMaxPoolPreparedStatementPerConnectionSize(30);ds.setTestWhileIdle(true);ds.setTestOnReturn(false);ds.setTestOnBorrow(false);ds.init();return ds;}static {//初始化write...try {write=getDruidDataSource("jdbc:mysql://127.0.0.1:3306/tianjl?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true","root","tianjingle");} catch (SQLException throwables) {throwables.printStackTrace();}//初始化讀庫(kù)// reader.add(write);// reader.add(write);// reader.add(write);}public DruidPooledConnection getConnection() throws SQLException {//這塊可以寫具體得庫(kù)選擇邏輯,讀庫(kù)隨機(jī)可以從用random方法。return write.getConnection();}}
(name = "dataO")public SqlSessionFactoryBean getSqlSessionFactoryOne1() throws Exception {//xml和實(shí)體的映射SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(new MyDataSource());sqlSessionFactoryBean.setTypeAliasesPackage("com.example.demo.one");Resource[] resources = new Resource[]{new ClassPathResource("tian/one/OneMapper.xml")};sqlSessionFactoryBean.setMapperLocations(resources);sqlSessionFactoryBean.setPlugins(new MybatisLanjieqi());return sqlSessionFactoryBean;}(name = "dataTwo")public MapperFactoryBean getSqlSessionFactoryTwo() throws Exception {//xml和實(shí)體的映射SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(new MyDataSource());sqlSessionFactoryBean.setTypeAliasesPackage("com.example.demo.two");sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("tian/two/TwoMapper.xml"));//單個(gè)數(shù)據(jù)源所有的數(shù)據(jù)庫(kù)映射MapperFactoryBean mapperFactoryBean=new MapperFactoryBean();//設(shè)置sqlSessionTemplate,zhuru yong demapperFactoryBean.setMapperInterface(TwoMapper.class);mapperFactoryBean.setSqlSessionFactory(sqlSessionFactoryBean.getObject());return mapperFactoryBean;}
晚安~
