资源,读取资源文件。有很多方法通过加载并解析资源文件,返回不同类型的IO流对象。
SqlSessionFactory的创建需要使用sqlSessionFactoryBuilder对象的build()方法。事实上使用SqlSessionFactoryBuilder的原因是将SqlSessionFactory这个复杂对象的创建交给Builder来执行,也就是建造者模式。
建造者模式:又称生成器模式,是一种对象的创建模式。可以将一个产品的内部表象与生成过程分割开,从而可以使一个建造过程生成具有不同内部表象的产品(将一个复杂对象的构建与它的表示分离,使得同样的构建可以创建不同的表示) 这样用户只需要指定需要建造的类型就可以得到具体的产品,不需要了解具体的建造过程和细节
在建造者模式中,角色分为指导者(Director)和建造者(builder):用户联系指导者,指导者指挥建造者最终得到产品。建造者模式可以强制执行分步骤建造过程。
SqlSessionFactory是一种重量级对象(系统开销大的对象),线程安全,所以一个应用只需要一个该对象即可。创建SqlSession对象使用SqlSessionFactory接口的openSession()方法。
默认的openSession()方法没有参数,它创建有如下特性的SqlSession对象:
SqlSession对象用于执行持久化操作,一个SqlSession对应着一次数据库会话。一次会话以SqlSession的创建开始,以SqlSession的关闭结束。
SqlSession对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其close()方法将其关闭。再次需要会话,再次开启。
SqlSession内部超过20个方法,我们常用的都是执行语法相关的方法。这些方法被用来执行定义在Sql映射的XML文件中SELECT、UPDATE、INSERT、DELETE语句,他们都会自行解释,每一句都使用语句的ID属性和参数对象,参数可以是原生类型(自动装箱或包装类)、JavaBean、PoJo或者Map。
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
/*
selectOne和selectList不同仅仅是因为selectOne必须返回一个对象或者null,如果返回值超过一个就会抛出异常。
selectMap会将返回对象中的属性作为key值,将对象作为value值,从而将多结果集转换为Map类型。
因为不是所有的语句都需要参数,所以这些方法都重载成为不需要参数的形式。
*/
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.12version>
dependency>
#Global logging configuration info warning error
log4j.rootLogger=DEBUG,stdout
#console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
settings>
...
configuration>
ThreadLocal并非一个线程的本地实现版本,它并不是一个Thread,而是一个threadlocalvariable(线程局部变量)。它的功能十分简单,为每一个使用该变量的线程都提供一个变量值副本,是java中较为特殊的一种线程绑定机制,其中每一个线程都可以独立的改变自己的副本,而不会与其他线程副本冲突。
public class MybatisUtil {
private static ThreadLocal<SqlSession> threadLocal=new ThreadLocal<>();
private static SqlSessionFactory sqlSessionFactory;
/**
* 加载配置文件
*/
static {
try {
Reader reader = Resources.getResourceAsReader("mybatis.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取sqlSession
* @return
*/
public static SqlSession getSqlSession(){
SqlSession sqlSession=threadLocal.get();
if(sqlSession==null){
sqlSession = sqlSessionFactory.openSession();
threadLocal.set(sqlSession);
}
return sqlSession;
}
/**
* 关闭sqlSession
*/
public static void closeSqlSession(){
SqlSession sqlSession=threadLocal.get();
if(sqlSession==null){
sqlSession.close();
threadLocal.remove();
}
}
}
public interface TeamDao {
/**
* 查询全部队伍
* @return
*/
List<Team> queryAll();
/**
* 根据队伍ID查询
* @param teamId
* @return
*/
Team queryById(Integer teamId);
/**
* 新增队伍
* @param team
* @return
*/
Integer add(Team team);
/**
* 更新队伍
* @param team
* @return
*/
Integer update(Team team);
/**
* 删除队伍
* @param teamId
* @return
*/
Integer delete(Integer teamId);
}
public class TeamDaoImpl implements TeamDao {
@Override
public List<Team> queryAll() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
List<Team> list = sqlSession.selectList("com.jsonliu.test.entity.Team.queryAll");
MybatisUtil.closeSqlSession();
return list;
}
@Override
public Team queryById(Integer teamId) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
Team team=sqlSession.selectOne("com.jsonliu.test.entity.Team.queryById",teamId);
MybatisUtil.closeSqlSession();
return team;
}
@Override
public Integer add(Team team) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
int num = sqlSession.insert("com.jsonliu.test.entity.Team.insert", team);
sqlSession.commit();
MybatisUtil.closeSqlSession();
return num;
}
@Override
public Integer update(Team team) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
int num =sqlSession.update("com.jsonliu.test.entity.Team.update",team);
sqlSession.commit();
MybatisUtil.closeSqlSession();
return num;
}
@Override
public Integer delete(Integer teamId) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
int num =sqlSession.delete("com.jsonliu.test.entity.Team.delete",teamId);
sqlSession.commit();
MybatisUtil.closeSqlSession();
return num;
}
}
public class TestB {
private TeamDao teamDao=new TeamDaoImpl();
@Test
public void test1(){
System.out.println("------------------queryAll----------------------");
List<Team> teams = teamDao.queryAll();
teams.forEach(team -> {
System.out.println(team);
});
System.out.println("------------------add----------------------");
Integer insert = teamDao.add(new Team("探险者", "新泽西", new Date()));
System.out.println("新增结果:"+insert);
System.out.println("------------------query----------------------");
Team team = teamDao.queryById(1115);
System.out.println(team);
System.out.println("------------------update----------------------");
team.setTeamName("JK的队伍");
team.setLocation("hangzhou");
Integer update = teamDao.update(team);
System.out.println("修改结果:"+insert);
System.out.println("------------------delete----------------------");
Integer delete = teamDao.delete(1115);
System.out.println("删除结果:"+delete);
}
}
前面的例子中,dao实现类并没做什么实质性的事情,仅仅通过sqlSession的相关API定位到mapper中相应id的sql语句。真正对DB进行操作是Mapper中的SQL完成的。
所以,Mybatis抛开了dao的实现类,直接定位到映射文件mapper中相应的sql语句,对DB进行操作。这种Dao的实现方式被称为Mapper接口的动态代理实现。
Mapper动态代理无需程序员实现dao接口,接口是Mybatis结合映射文件生成的动态代理实现的。
public interface TeamMapper {
/**
* 查询全部队伍
* @return
*/
List<Team> queryAll();
/**
* 根据队伍ID查询
* @param teamId
* @return
*/
Team queryById(Integer teamId);
/**
* 新增队伍
* @param team
* @return
*/
Integer insert(Team team);
/**
* 更新队伍
* @param team
* @return
*/
Integer update(Team team);
/**
* 删除队伍
* @param teamId
* @return
*/
Integer delete(Integer teamId);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jsonliu.test.mapper.TeamMapper">
<select id="queryAll" resultType="com.jsonliu.test.entity.Team">
select * from team
select>
<select id="queryById" parameterType="int" resultType="com.jsonliu.test.entity.Team">
select * from team where teamId=#{id}
select>
<insert id="insert" parameterType="com.jsonliu.test.entity.Team">
insert into team(teamName,location,createTime)
values(#{teamName},#{location},#{createTime})
insert>
<update id="update" parameterType="com.jsonliu.test.entity.Team">
update team set teamName=#{teamName},location=#{location} where teamId=#{teamId}
update>
<delete id="delete" parameterType="int">
delete from team where teamId=#{teamId}
delete>
mapper>
<configuration>
...
<mappers>
<mapper resource="com/jsonliu/test/entity/Team.xml"/>
<mapper resource="com/jsonliu/test/mapper/TeamMapper.xml"/>
mappers>
configuration>
只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。
public class TeamMapperTest {
@Test
public void test1(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
TeamMapper teamDao = sqlSession.getMapper(TeamMapper.class);
System.out.println("------------------queryAll----------------------");
List<Team> teams = teamDao.queryAll();
teams.forEach(team -> {
System.out.println(team);
});
System.out.println("------------------add----------------------");
Integer insert = teamDao.insert(new Team("探险者23", "新泽西23", new Date()));
System.out.println("新增结果:"+insert);
System.out.println("------------------query----------------------");
Team team = teamDao.queryById(1116);
System.out.println(team);
System.out.println("------------------update----------------------");
team.setTeamName("wangwu的队伍");
team.setLocation("tianjin");
Integer update = teamDao.update(team);
System.out.println("修改结果:"+insert);
System.out.println("------------------delete----------------------");
Integer delete = teamDao.delete(1116);
System.out.println("删除结果:"+delete);
}
}