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> </typeAliases> <environments default="HD"> <environment id="HD"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <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> </environments> <mappers> <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); }
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)){ String driver="oracle.jdbc.driver.OracleDriver",url="jdbc:oracle:thin:@"+hotel.getIp()+":"+hotel.getPort()+":"+hotel.getSid(); 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; } } @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){ if(dataSoruce.size()>=MaxDataSourceSize){ removeFirstMap(); } dataSoruce.put(id, sqlSessionFactory); } else return null; } SqlSession sqlSession = sqlSessionFactory.openSession(); Object idal = sqlSession.getMapper(clazz); return (T)IDALProxy.bind(idal, sqlSession); } else return null; } 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(); } } @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();
Hotel实体中存了数据库的IP地址,端口号等基本信息,根据hotel生成对应库的Mapper实例进行数据操作。
通过IDALProxy类对生成Mapper实例的所有方法进行了再次封装,实现数据库资源的提交,缓存清空和释放。