简介:本案例是使用使用mybatis来增删改查的一个实例, 它的数据源是多个的,可以随意切换,这在数据量比较大的项目中还是经常要用到的哦。 简单的说有点意思,哈哈。最后测试由于刚好有httpclients的代码就之间拿过来用了。
操作的实体类:
public class User {
private int id;
private String username;
private String password;
private String salt;
get/set方法省略/
}
数据属性配置文件mybatis-config-datasource.properties
使用mysql数据库,其中%DBNAME%会根据实际情况替换实际连接的数据库。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/%DBNAME%
username=root
password=123456
数据库连接配置文件:mybatis-config.xml
使用了C3P0连接池
红色字体部分(最后三行)配置了实体操作配置文件路径
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<configuration>
<settings>
<!-- 全局映射器启用缓存 -->
<setting name="cacheEnabled" value="false" />
<!-- 查询时,关闭关联对象即时加载以提高性能 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指定),不会加载关联表的所有字段,以提高性能 -->
<setting name="aggressiveLazyLoading" value="false" />
<!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
<setting name="multipleResultSetsEnabled" value="true" />
<!-- 允许使用列标签代替列名 -->
<setting name="useColumnLabel" value="true" />
<!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 给予被嵌套的resultMap以字段-属性的映射支持 -->
<setting name="autoMappingBehavior" value="FULL" />
<!-- 对于批量更新操作缓存SQL以提高性能 -->
<!-- <setting name="defaultExecutorType" value="BATCH" /> -->
<!-- FORSQLSERVER -->
<setting name="defaultExecutorType" value="SIMPLE" />
<!-- 数据库超过25000秒仍未响应则超时 -->
<setting name="defaultStatementTimeout" value="25000" />
</settings>
<typeAliases>
<typeAlias type="com.qing.datasource.C3P0DataSourceFactory" alias="C3P0" />
</typeAliases>
<environments default="DAG">
<environment id="DAG">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="C3P0">
<property name="driverClass" value="${driver}" />
<property name="jdbcUrl" value="${url}" />
<property name="user" value="${username}" />
<property name="password" value="${password}" />
<property name="preferredTestQuery" value="SELECT 1" />
<property name="acquireIncrement" value="3" />
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="maxIdleTime" value="60" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="sqlmapper/UserMapper.xml"/>
</mappers>
</configuration>
数据库切换的初始化
public class DBNameUtil {
private Map<String,String> map = new HashMap<String,String>();
private static DBNameUtil dbName = new DBNameUtil();
private DBNameUtil(){
map.clear();
map.put("dag1", "test");
map.put("dag2", "shiro");
map.put("dag3", "shiroweb");
}
public String getDBName(String dagId){
return map.get(dagId);
}
public static DBNameUtil getInstance(){
return dbName;
}
}
现在我们应该把这两个配置文件里的数据组合起来
创建Mybatis SqlSessionFactory实例
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.util.StringUtils;
import com.qing.utils.DBNameUtil;
/**
* 构造指定DAG ID的Mybatis SqlSessionFactory实例,并进行全局缓存.
*/
public final class DataSourceSqlSessionFactoryBuilder {
private DataSourceSqlSessionFactoryBuilder() {};
/**
* Mybatis配置文件名.
*/
private static final String MYBATIS_CONFIG = "mybatis-config.xml";
/**
* Mybatis数据源属性配置文件.
*/
private static final String MYBATIS_CONFIG_PROPERTIES = "mybatis-config-datasource.properties";
/**
* 缓存每个DAG对应的Mybatis数据源.
*/
private static final Map<String, SqlSessionFactory> DATASOURCE = new ConcurrentHashMap<String, SqlSessionFactory>();
public static SqlSessionFactory buildSqlSessionFactory(String dagID)
throws IOException {
if (StringUtils.isEmpty(dagID)) {
throw new IOException("The DAG id is Empty!");
}
if (DATASOURCE.get(dagID) != null) {
System.out.println("DDR: get dataSource from cache width dagid[{" + dagID + "}].");
return DATASOURCE.get(dagID);
}
String dbName = DBNameUtil.getInstance().getDBName(dagID);
if (dbName == null) {
throw new IOException("The DAG id is not found! " + dagID);
}
Properties properties = null;
SqlSessionFactory sqlSessionFactory = null;
InputStream inputStream = Resources.getResourceAsStream(MYBATIS_CONFIG);
properties = Resources.getResourceAsProperties(MYBATIS_CONFIG_PROPERTIES);
String url = properties.getProperty("url").toString().replace("%DBNAME%", dbName);
properties.setProperty("url", url);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,properties);
DATASOURCE.put(dagID, sqlSessionFactory);
System.out.println("DDR: build dataSource with dagId[{" + dagID + "}] and domain[{" + dbName + "}].");
return DATASOURCE.get(dagID);
}
}
有了SqlSessionFactory,现在就要创建SqlSession了,但是为方便管理,并且考虑到线程安全以及事物,我们建立一个SessionManager类。
import java.sql.SQLException;
import org.apache.ibatis.session.SqlSession;
/**
* 管理线程上下文持有的 Mybatis SqlSession实例.
*/
public final class SessionManager {
private SessionManager(){};
//当前线程上下文,持有Mybatis SqlSession对象.
private static ThreadLocal<SqlSession> sqlSessionHolder = new ThreadLocal<SqlSession>();
//获取当前线程持有的SqlSession对象实例.
public static SqlSession getSqlSession() {
return sqlSessionHolder.get();
}
//设置当前线程持有的SqlSession实例.
public static void setSqlSession(SqlSession sqlSession) {
sqlSessionHolder.set(sqlSession);
}
/**
* 使用当前线程的SqlSession实例构造指定Mapper实例的代理对象.
* @param clazz Mapper接口类型.
* @return
*/
public static <T> T get(Class<T> clazz) {
SqlSession session = sqlSessionHolder.get();
try {
System.out.println("==> dataSource: {}"+session.getConnection().getMetaData().getURL());
} catch (SQLException e) {
e.printStackTrace();
}
return sqlSessionHolder.get().getMapper(clazz);
}
//关闭当前线程持有的SqlSession实例并从其ThreadLocal上下文实例中移除.
public static void close() {
if (sqlSessionHolder.get() != null) {
sqlSessionHolder.get().close();
}
sqlSessionHolder.remove();
}
/**
* 进行数据库事务提交.
* @param deltegate 回调接口.
* @throws Exception
*/
public static void transactional(TransactionDelegate deltegate) throws Exception{
SqlSession session = sqlSessionHolder.get();
try {
System.out.println("==> dataSource: {}"+session.getConnection().getMetaData().getURL());
} catch (SQLException e) {
e.printStackTrace();
}
try{
session.commit(false);
deltegate.execute(session);
session.commit();
}catch(Exception ex){
session.rollback();
throw ex;
}finally{
session.commit(true);
}
}
//事务代理接口
public interface TransactionDelegate{
public void execute(SqlSession session) throws Exception;
}
}
最后就是创建操作实体的接口,以及实体相关配置了
UserMapper.xml
<?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="com.qing.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.qing.entity.User">
<result column="id" jdbcType="TINYINT" property="id" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="salt" jdbcType="VARCHAR" property="salt" />
</resultMap>
<sql id="Base_Column_List">
id,username,password,salt
</sql>
<select id="findByUserName" parameterType="java.lang.String" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM sys_user_test
WHERE username = #{username}
</select>
<insert id="save" parameterType="com.qing.entity.User" useGeneratedKeys="false">
INSERT INTO sys_user_test (id
,username
,password
,salt
) VALUES (
#{id}
,#{username}
,#{password}
,#{salt}
)
</insert>
<update id="updateUser" parameterType="com.qing.entity.User">
UPDATE sys_user_test
<set >
<if test="id != null" >
id = #{id},
</if>
<if test="username != null">
username = #{username},
</if>
<if test="password != null">
password = #{password},
</if>
<if test="salt != null">
salt = #{salt},
</if>
</set>
WHERE id = #{id}
</update>
</mapper>
操作数据库接口
public interface UserMapper {
List<User> findByUserName(String username);
void save(User user);
int updateUser(User user);
}
测试:
新建一个测试的servlet
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("====================MyServlet 我来啦 ==================");
String dagId = request.getParameter("dagId");
System.out.println("dagId================>"+dagId);
System.out.println("dbName================>"+DBNameUtil.getInstance().getDBName(dagId));
SqlSessionFactory sqlSessionFactory = DataSourceSqlSessionFactoryBuilder.buildSqlSessionFactory(dagId);
SessionManager.setSqlSession(sqlSessionFactory.openSession(true));
User user = new User();
user.setId(5);
user.setUsername("wang");
user.setPassword("2345134");
user.setSalt(DBNameUtil.getInstance().getDBName(dagId)+user.getId());
SessionManager.get(UserMapper.class).save(user);
}
把项目放到tomcat下面启动。
使用的是HttpClients进行测试
public class Test1 {
/**
* 发送 post请求访问本地应用并根据传递参数不同返回不同结果
*/
public void post() {
// 创建默认的httpClient实例.
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建httppost
HttpPost httppost = new HttpPost("http://localhost:8080/mybatis/MyServlet");
// 创建参数队列
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("dagId", "dag2"));
UrlEncodedFormEntity uefEntity;
try {
uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
httppost.setEntity(uefEntity);
System.out.println("executing request " + httppost.getURI());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println("--------------------------------------");
System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));
System.out.println("--------------------------------------");
}
} finally {
response.close();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭连接,释放资源
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Test1 t = new Test1();
t.post();
}
}