Mybatis攔截器實現(xiàn)讀寫分離的思路和實踐
說到這里,我們可以再思考一個問題,一般數(shù)據(jù)庫都是主從,也就是很多都是一主多從,對應(yīng)的就是一寫多讀,意思是寫的時候?qū)懙街鲙欤x的時候可以從從庫的任意中讀取。因此我們的插件要有寫庫的數(shù)據(jù)源已經(jīng)多個讀庫的數(shù)據(jù)源。
上邊說了那么多,如果沒有讀寫識別的信號,那說的再多也沒有價值。這塊我們就需要解析SQL或者解析方法上邊的特定注解了。前者為一般模式,后者是靈活配置。當(dāng)然這塊要注意的就是事務(wù)了,事務(wù)肯定要操作單庫,也必然是主庫,道理說了挺多哈。我們試著研究一下怎么做吧。
1.首先就是Mybatis插件了,記得之前我們說mybatis有4個階段(Executor、ParameterHandler、ResultSetHandler 以及 StatementHandler),每個階段的各個方法都可以被攔截,當(dāng)然這塊攔截器的攔截原理責(zé)任鏈模式,過程還是比較難的。然后通過jdk代理的方式植入到mybatis執(zhí)行過程中。這塊的筆記已經(jīng)忘的差不多了。再此貼個筆記。
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)場的一些東西傳過來,比如調(diào)用類的信息。當(dāng)然還有sql的類型什么的。這塊我們debug一下??纯次覀兊腟tatementHandler中有什么值。


public class MyDataSource extends DruidDataSource {private static DruidDataSource write;private static Listreader;//模擬多庫初始化....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();}//初始化讀庫// reader.add(write);// reader.add(write);// reader.add(write);}public DruidPooledConnection getConnection() throws SQLException {//這塊可以寫具體得庫選擇邏輯,讀庫隨機(jī)可以從用random方法。return write.getConnection();}}
(name = "dataO")public SqlSessionFactoryBean getSqlSessionFactoryOne1() throws Exception {//xml和實體的映射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和實體的映射SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(new MyDataSource());sqlSessionFactoryBean.setTypeAliasesPackage("com.example.demo.two");sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("tian/two/TwoMapper.xml"));//單個數(shù)據(jù)源所有的數(shù)據(jù)庫映射MapperFactoryBean mapperFactoryBean=new MapperFactoryBean();//設(shè)置sqlSessionTemplate,zhuru yong demapperFactoryBean.setMapperInterface(TwoMapper.class);mapperFactoryBean.setSqlSessionFactory(sqlSessionFactoryBean.getObject());return mapperFactoryBean;}
晚安~
評論
圖片
表情
