基于SQL语句的Spring多数据源配置

来源:互联网 发布:淘宝u站关闭了 编辑:程序博客网 时间:2024/05/26 15:54

本文源码下载:

https://pan.baidu.com/s/1o7Rlbfk

当项目发展到一定规模,必定设计到数据库的拆分,从而用到双数据源、多数据源。传统的配置多式注解方式,配置复杂,且不易使用。本文采取的是通过sql语句的方式,在sql层实现动态切换数据源,且只需额外配置一个spring bean即可,没有复杂内容

用法

1、将上面链接的代码下载,引入项目中。

2、在Spring配置文件中配置两个或更多数据源,例:

    <bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>        <property name="url" value="jdbc:mysql://localhost:3306/test1"></property>        <property name="username" value="root"></property>        <property name="password" value="root"></property>    </bean>    <bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>        <property name="url" value="jdbc:mysql://localhost:3306/test2"></property>        <property name="username" value="root"></property>        <property name="password" value="root"></property>    </bean>

3、配置MultipleDataSource

 <!--数据源智能切换-->    <bean id="dataSource" class="com.core.jdbc.MultipleDataSource">        <!--没有指定数据源时,默认用dataSource1-->        <property name="defaultDataSource" ref="dataSource1"></property>        <property name="dataSourceMap">            <map>                <entry key="test1" value-ref="dataSource1"></entry>                <entry key="test2" value-ref="dataSource2"></entry>            </map>        </property>        <!--数据源数量比较少时,用true,比较多用false.-->        <property name="eager" value="true"/>    </bean>

在SQL查询时,SQL语句前面加上[数据源id],这里的数据源id是dataSourceMap的key。

例如:

 public static void main(String[] args) {        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");        DataSource dataSource = applicationContext.getBean("dataSource", DataSource.class);        System.out.println(dataSource);        Connection connection = null;        try{            connection = dataSource.getConnection();            //执行test1数据源的查询:            ResultSet rs1 = connection.prepareStatement("[test1] select * from test").executeQuery();            while (rs1.next()){                // ...            }            //执行test2数据源的查询:            ResultSet rs2 = connection.prepareStatement("[test2] select * from test").executeQuery();            while (rs2.next()){                // ...            }            //执行默认数据源defaultDataSource的查询            ResultSet rs = connection.prepareStatement("select * from test").executeQuery();            while (rs.next()){                // ...            }        }catch (SQLException e){            e.printStackTrace();        }finally {            try {                connection.close();            } catch (SQLException e) {                e.printStackTrace();            }        }    }

原理

核心类是BaseMultipleConnection,里面定义了如何切换、执行。

内部类Executor是一个工具类,相当于执行器,将sql语句分发到真实的connection上去执行。

   protected static class Executor{        private Connection connection;        private String sql;        public Executor(Connection connection, String sql) {            this.connection = connection;            this.sql = sql;        }    // 执行的方法... }

这三个抽象方法定义了如何确定Connection,以及维护Connection的状态。

    protected abstract Connection getConnection(String id) throws SQLException;    protected abstract Connection getDefaultConnection() throws SQLException;    protected abstract List<Connection> getConnections() throws SQLException;

核心方法getExecutor,从sql语句中提取出id,交给Executor去执行。

 protected final Executor getExecutor(String sql) throws SQLException{        if(sql == null){            throw new IllegalArgumentException("the sql is null!");        }        if(sql.isEmpty()){            throw new IllegalArgumentException("the sql is empty!");        }        sql = sql.trim();        if(sql.startsWith("[")){            int index = sql.indexOf(']');            if(index <= 1 || index == sql.length() - 1){                throw new IllegalArgumentException("illegal id token.");            }            String id = sql.substring(1,index);            String realSql = sql.substring(index + 1);            return getExecutor(id,realSql);        }else{            return getDefault(sql);        }    }

支持

mybatis

直接修改mybatis的sql语句即可

hibernate

用拦截器

看看官方文档吧http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html
还有这篇http://www.iteye.com/topic/866142

主要就是继续EmptyInterceptor,重载onPrepareStatement(sql)方法

原创粉丝点击