Mybatis动态数据源实现

来源:互联网 发布:恐怖整蛊软件 编辑:程序博客网 时间:2024/04/19 11:41

Mybatis数据库文件配置是在项目启动时初始化数据工厂的,初始化过程仅为1次,当数据库地址改变时需修改配置文件重新启动项目,无法动态加载数据源。 
Mybatis连接数据库底层核心库SqlSessionFactory,项目初始化也是生成该类,并缓存,该需求需要通过编程根据不同数据源动态生成SqlSessionFactory实例。 
核心代码:

        String driver="oracle.jdbc.driver.OracleDriver",url="jdbc:oracle:thin:@127.0.0.1:1521:orcl";        ///mysql        //driver = "com.mysql.jdbc.Driver";        //url = "jdbc:mysql://"+hotel.getIp()+":"+hotel.getPort()+"/"+hotel.getDatabase();        //初始化数据库属性        Properties properties = new Properties();        properties.setProperty("jdbc.driver",driver);          properties.setProperty("jdbc.url", url);          properties.setProperty("jdbc.username",hotel.getUsername());          properties.setProperty("jdbc.password",hotel.getPassword());        Reader reader = Resources.getResourceAsReader(HotelFactory.configuration);        //创建数据工厂        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();        SqlSessionFactory sqlSessionFactory = builder.build(reader, properties);        SqlSession sqlSession = sqlSessionFactory.openSession();        HotelMapper hotelMapper = sqlSession.getMapper(HotelMapper.class);        hotelMapper.getHotelById(1);        //释放会话        sqlSession.clearCache();        sqlSession.close();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

configuration.xml Mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>   <!DOCTYPE configuration   PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>    <typeAliases>        <!--给实体类起一个别名 user         <typeAlias type="entity.Hotel" alias="Hotel" />        <typeAlias type="entity.Room" alias="Room" />        -->    </typeAliases>    <!--数据源配置  使用mysql数据库 -->    <environments default="HD">        <environment id="HD">            <transactionManager type="JDBC" />            <dataSource type="POOLED">                <!-- 并发最大连接数 默认10-->                <property name="poolMaximumActiveConnections" value="1000"/>                <property name="driver" value="${jdbc.driver}" />                <property name="url" value="${jdbc.url}" />                <property name="username" value="${jdbc.username}" />                <property name="password" value="${jdbc.password}" />            </dataSource>        </environment><!--        <environment id="HO">              <transactionManager type="JDBC" />              <dataSource type="POOLED">                  <property name="driver" value="oracle.jdbc.driver.OracleDriver" />                  <property name="url" value="jdbc:oracle:thin:@192.168.1.17:1521:orcl" />                  <property name="username" value="hotel" />                  <property name="password" value="q123" />              </dataSource>          </environment>   -->    </environments>    <mappers>        <!-- userMapper.xml装载进来  同等于把“dao”的实现装载进来 -->        <mapper resource="mapper/HotelMapper.xml"/>        <mapper resource="mapper/RestaurantMapper.xml"/>        <mapper resource="mapper/RoomsMapper.xml"/>        <mapper resource="mapper/MeetingsMapper.xml"/>    </mappers></configuration> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

HotelMapper

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="mapper.HotelMapper">    <select id="getHotelById" resultType="entity.Hotel">        select * from HOTEL        where ID = #{id,jdbcType=DECIMAL}    </select></mapper>    public interface HotelMapper {        Hotel getHotelById(@Param("id") int id);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12


SqlSessionFactory只是记载的数据库的连接属性,并未与数据库连接,并不占用数据库及系统资源。 

SQLSession便于数据库建立连接了,每次读取数据后若不释放,数据库的连接数不断增加,当超过数据库的最大连接数或者内存溢出均会导致程序崩溃。 

每次连接都需要初始化,过于麻烦,可封装套数据工厂,缓存相关信息。 

设计思路1:缓存SqlSessionFactory,通过java动态代理释放数据库资源即SqlSession。(适用多点,SqlSession数量不可控情况) 
设计思路2:缓存SqlSessionFactory及SqlSession,SqlSession会默认缓存已调用的方法,通过sqlSession.clearCache()清空默认缓存,保证读取的是实时数据库。(适用单点或少数站点机,SqlSession数量可控情况)

设计思路1核心代码: 
数据工厂DataSourceFactory代码:

package factory;import java.io.Reader;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.net.InetSocketAddress;import java.net.Socket;import java.net.SocketAddress;import java.util.HashMap;import java.util.Map;import java.util.Properties;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import entity.Hotel;@SuppressWarnings("finally")public class DataSourceFactory {    //酒店数据工作缓存数量    private static final int MaxDataSourceSize=10;    //端口超时时间    private static final int TimeOut = 2000;    //酒店数据工厂缓存    private static Map<Integer,SqlSessionFactory> dataSoruce;    static{        dataSoruce = new HashMap<Integer, SqlSessionFactory>(MaxDataSourceSize);    }    //删除第一个元素    private static void removeFirstMap(){        for (Integer key : dataSoruce.keySet()) {              dataSoruce.remove(key);            break;        }      }    //删除酒店缓存    public static void removeHotel(int hotelid){        dataSoruce.remove(hotelid);    }    //检测连接是否可用    public static boolean isConnection(Hotel hotel){        Boolean result = false;        try{            //检查端口是否开放            Socket client = new Socket();            SocketAddress socketAddress = new InetSocketAddress(hotel.getIp(),Integer.parseInt(hotel.getPort()));            client.connect(socketAddress,TimeOut);            client.close();            result = true;        }        catch(Exception e){            e.printStackTrace();            result = false;        }        finally{            return result;        }    }    public static boolean isConnection(Integer id){        Boolean result = false;        try{            Hotel hotel = HotelFactory.getHotelById(id);            if(hotel != null){                //检查端口是否开放                Socket client = new Socket();                SocketAddress socketAddress = new InetSocketAddress(hotel.getIp(),Integer.parseInt(hotel.getPort()));                client.connect(socketAddress,TimeOut);                client.close();                result = true;            }        }        catch(Exception e){            e.printStackTrace();            result = false;        }        finally{            return result;        }    }    private static SqlSessionFactory createSqlSessionFactory(Integer id){        SqlSessionFactory _sqlSessionFactory = null;        try{            Hotel hotel = HotelFactory.getHotelById(id);            if(hotel != null && isConnection(hotel)){                //数据库匹配           Oracle/Mysql                String driver="oracle.jdbc.driver.OracleDriver",url="jdbc:oracle:thin:@"+hotel.getIp()+":"+hotel.getPort()+":"+hotel.getSid();                ///mysql                //driver = "com.mysql.jdbc.Driver";                //url = "jdbc:mysql://"+hotel.getIp()+":"+hotel.getPort()+"/"+hotel.getDatabase();                //初始化数据库属性                Properties properties = new Properties();                properties.setProperty("jdbc.driver",driver);                  properties.setProperty("jdbc.url", url);                  properties.setProperty("jdbc.username",hotel.getUsername());                  properties.setProperty("jdbc.password",hotel.getPassword());                Reader reader = Resources.getResourceAsReader(HotelFactory.configuration);                //创建数据工厂                SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();                _sqlSessionFactory = builder.build(reader, properties);            }        }        catch(Exception e){            e.printStackTrace();        }        finally{            return _sqlSessionFactory;        }    }    //根据酒店id获取Mapper    @SuppressWarnings("unchecked")    public static <T> T getMapper(Integer id,Class<?> clazz){        if(isConnection(id)){            SqlSessionFactory sqlSessionFactory = dataSoruce.get(id);            if(sqlSessionFactory==null){                //创建数据工厂                sqlSessionFactory = createSqlSessionFactory(id);                if(sqlSessionFactory != null){                    //排序算法 删除Map序列第一个元素,并将当前元素移至Map序列的首位                    if(dataSoruce.size()>=MaxDataSourceSize){                        removeFirstMap();                    }                    dataSoruce.put(id, sqlSessionFactory);                }                else                    return null;            }            /*else{                //排序算法 将当前元素移至Map序列的首位                dataSoruce.remove(id);                dataSoruce.put(id, sqlSessionFactory);            }*/            SqlSession sqlSession = sqlSessionFactory.openSession();            Object idal = sqlSession.getMapper(clazz);            return (T)IDALProxy.bind(idal, sqlSession);        }        else            return null;    }    //动态加载  SqlSession提交,释放    public static class IDALProxy implements InvocationHandler {        private Object idal;        private SqlSession sqlSession;        private IDALProxy(Object idal, SqlSession sqlSession) {            this.idal = idal;            this.sqlSession = sqlSession;        }        public static Object bind(Object idal, SqlSession sqlSession) {            return Proxy.newProxyInstance(idal.getClass().getClassLoader(),idal.getClass().getInterfaces(), new IDALProxy(idal, sqlSession));        }        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {            Object object = null;            try {                object = method.invoke(idal, args);            } catch(Exception e) {                sqlSession.rollback();                e.printStackTrace();            } finally {                sqlSession.commit();                sqlSession.clearCache();                sqlSession.close();            }            return object;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186

酒店工厂HotelFactory代码:

package factory;import java.io.InputStream;import java.io.Reader;import java.util.Properties;import mapper.HotelMapper;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import entity.Hotel;public class HotelFactory {    public static SqlSessionFactory sqlSessionFactory = null;    //数据库属性值    public static final String jdbc_properties="jdbc.properties";    //数据库配置文件    public final static String configuration = "configuration.xml";    //创建本地酒店管理数据库    static{        try {            Properties properties = new Properties();            InputStream in = Resources.getResourceAsStream(jdbc_properties);            properties.load(in);            String driver = properties.getProperty("jdbc.driverClassName");            String url = properties.getProperty("jdbc.url");            String username = properties.getProperty("jdbc.username");            String password = properties.getProperty("jdbc.password");            properties.setProperty("jdbc.driver",driver);              properties.setProperty("jdbc.url", url);              properties.setProperty("jdbc.username",username);              properties.setProperty("jdbc.password",password);            Reader reader = Resources.getResourceAsReader(configuration);            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();            sqlSessionFactory = builder.build(reader, properties);        } catch (Exception e) {            e.printStackTrace();        }    }    //根据id获取酒店实体    @SuppressWarnings("finally")    public static Hotel getHotelById(Integer id){        Hotel hotel = null;        SqlSession sqlSession = null;        try{            sqlSession = sqlSessionFactory.openSession();            hotel = sqlSession.getMapper(HotelMapper.class).getHotelById(id);        }        catch(Exception e){            e.printStackTrace();        }        finally{            if(sqlSession != null)                sqlSession.close();            return hotel;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

引用实例:

RoomsMapper roomMapper = getMapper(hotelid);roomMapper.getRoom();
  • 1
  • 2

Hotel实体中存了数据库的IP地址,端口号等基本信息,根据hotel生成对应库的Mapper实例进行数据操作。 
通过IDALProxy类对生成Mapper实例的所有方法进行了再次封装,实现数据库资源的提交,缓存清空和释放。

阅读全文
0 0
原创粉丝点击