一、MyBatis的简单介绍
MyBatis是一个优秀的持久层框架(MVC模型中的DAO层),它以xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
二、Mybatis的jar包介绍MyBatis的jar包介绍
因为MyBatis是DAO层的,要直接操作数据库,所以使用时还需要导入数据库的驱动包
三、配置文件
1、SqlMapConfig.xml(建议放在类路径下)。是mybatis核心配置文件,配置文件内容为数据源、事务管理。
// DTD约束配置
-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
2、Mapper1.xml、Mapper2.xml等。每个xml文件对应数据库的一张表
// DTD约束配置
-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3、日志文件的配置(文件名:log4j.properties。放在类路径下,方便我们在控制台查看程序的运行)
# Global logging configuration
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
四、实现简单的增删改查
1、SqlMapConfig.xml的配置
-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
2、mapper.xml的配置
-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
SELECT * FROM user WHERE id = #{id}
SELECT * FROM user WHERE username LIKE "%"#{v}"%"
SELECT LAST_INSERT_ID()
INSERT INTO user
(id,username,birthday,sex,address)
VALUES(#{id},#{username},#{birthday},#{sex},#{address})
UPDATE user SET
username=#{username},address=#{address}
WHERE id=#{id}
DELETE FROM user WHERE id=#{id}
3、pojo类的准备,和数据库对应,代码多,省略了方法)
package trd.mybatis.pojo;
import java.util.Date;
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
}
4、数据库的表
5、测试程序的步骤利用org.apache.ibatis.io.Resources将SqlMapConfig.xml文件加载进来(比如加载为输入流)
创建SqlSessionFactoryBuilder对象(直接 new)为builder
传入SqlMapConfig.xml的输入流,用builder对象来创建SqlSessionFactory对象,赋给factory
用factory创建SqlSession对象
执行SqlSession对象的对应方法,获取结果(如果涉及到操作表,还应该有提交)
打印结果
释放资源
6、测试类
package trd.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
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 org.junit.Before;
import org.junit.Test;
import trd.mybatis.pojo.User;
public class Test1 {
// 实际都是before方法赋值,因为Resources.getResourceAsStream()方法有异常
// 读取配置文件InputStream is = null;
// 创建SqlSessionFactoryBuilder对象SqlSessionFactoryBuilder builder = null;
// 创建SqlSessionFactory对象(before方法赋值)SqlSessionFactory factory = null;
// 用工厂创建SqlSession对象SqlSession session = null;
// 每次junit测试前调用此方法给对象赋值@Before
public void before() throws IOException{
is = Resources.getResourceAsStream("sqlMapConfig.xml");
builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
session = factory.openSession();
}
// 查询单个@Test
public void selectOne() throws IOException{
User user = session.selectOne("trd.mybatis.dao.MybatisDao.selectOne", 35);
System.out.println(user);
// 释放资源session.close();
}
// 查询多个用户(模糊查询)@Test
public void selectList() throws IOException{
List userList = session.selectList("trd.mybatis.dao.MybatisDao.selectList", "三");
for (User user : userList) {
// 循环遍历打印是为了看得更清晰System.out.println(user);
}
// 释放资源session.close();
}
// 插入用户(这里在配置文件中设置了主键值增长返回)@Test
public void insertUser() throws IOException{
// 表的id是主键自增长,所以这里没有给id赋值User user = new User("lisi","男", new Date(), "四川");
session.insert("trd.mybatis.dao.MybatisDao.insertUser", user);
System.out.println("插入用户之后,测试自增长的主键是否返回:"+user);
// 对数据有修改时就必须提交session.commit();
// 释放资源session.close();
}
// 根据id修改用户信息@Test
public void updateUser() throws IOException{
User user = new User("xiaoqiang", "男", new Date(), "重庆");
user.setId(35);
session.update("trd.mybatis.dao.MybatisDao.updateUser", user);
session.commit();
session.close();
}
// 根据id删除用户@Test
public void deleteUser() throws IOException{
session.delete("trd.mybatis.dao.MybatisDao.deleteUser", 39);
session.commit();
session.close();
}
}
五、MyBatis的Mapper动态代理方式编写DAO层
1、体现了面向切面编程的思想,利用了java提供的动态代理技术,调用SqlSession的getMapper(Class<> class)方法,传入DAO接口,并返回该接口的实现类。最终调用的是实现了InvocationHandler接口的实现类(追踪源码,可以发现这个实现类是org.apache.ibatis.binding.MapperProxy)的invoke方法,核心源码如下
2、Mapper接口开发需要遵循以下规范:Mapper.xml文件中的namespace与mapper接口的类路径相同。
Mapper接口方法名和Mapper.xml中定义的每个statement(增删改查标签)的id相同
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
3、Mapper动态代理测试的代码(配置文件就是上面的):
// dao接口package trd.mybatis.dao;
import java.util.List;
import trd.mybatis.pojo.User;
public interface MybatisDao {
/** 使用mapper动态代理的规范:* 1、接口的完整类名和mapper.xml的namespqce(命名空间)属性值相同* 2、方法名和对应的sql语句标签的id属性值相同* 3、输入参数类型和对应sql标签的parameterType的类型相同* 4、返回值类型和对应sql标签的resultType的类型相同*/
User selectOne(int i);
List selectList(String username);
int insertUser(User user);
int updateUser(User user);
int deleteUser(int id);
}
//==========================================================================// 测试类,为避免代码过多,这里只测了2个方法package trd.test;
import java.io.InputStream;
import java.util.List;
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 org.junit.Before;
import org.junit.Test;
import trd.mybatis.dao.MybatisDao;
import trd.mybatis.pojo.User;
public class ProxyTesr {
InputStream is = null;
SqlSessionFactoryBuilder builder = null;
SqlSessionFactory factory = null;
SqlSession session = null;
@Before
public void before() throws Exception {
is = Resources.getResourceAsStream("sqlMapConfig.xml");
builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
session = factory.openSession();
}
@Test
public void selectOne() throws Exception {
// 获取mapper动态代理产生的dao实现类MybatisDao mybatisDao = session.getMapper(MybatisDao.class);
// 调用相应的方法User user = mybatisDao.selectOne(35);
// 输出结果以检验mapper动态代理是否成功System.out.println(user);
}
@Test
public void insertUser() throws Exception {
MybatisDao mybatisDao = session.getMapper(MybatisDao.class);
User user = new User("lisi","男", new Date(), "四川");
mybatisDao.insertUser(user);
session.commit();
System.out.println(user);
}
}
六、结合规范和上面的源代码图片,猜测Mapper动态代理的实现过程:
SqlSession的session.getMapper(Class type)返回的接口实现类实际用了java的动态代理技术。在调用Proxy.newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)方法时,再调用interfaces参数getName()方法,获取到接口的类路径名。
在调用实现了InvocationHandler接口的实现类的invoke方法时,会传入增强方法的Method对象,可以利用Method对象的方法,获取该增强方法的方法名、返回值类型
接口的类路径名+增强方法的方法名可以拼凑出SqlSession的增删改查方法的第一个参数(该参数可以用来获取到Mapper.xml文件中指定的那个标签中的sql语句)
因为增强方法的方法名和statement(增删改查标签)的id相同,所以可以利用dom4j等技术,解析该xml文件,得到该id的标签(insert、delete、update、select主要就这4种)。
SqlSession对象的insert、delete、update这三种方法很简单,方法名就一种,所以不需要过多的判断
SqlSession对象的select有4种(select(...)、selectOne(....)、selectMap(...)、selectList(...))。可以判断增强方法的返回值类型来决定调用哪个select方法。返回的是List集合就调用selectList(...),返回Map集合调用selectMap(...),无返回值调用select(...),由于selectOne(....)返回的是泛型,不确定具体的返回类型,所有写在最后的else判断里
七、SqlMapConfig.xml的常用属性说明
2、全部属性配置的内容及顺序要求1、properties(属性)
2、settings(全局配置参数)
3、typeAliases(类型别名)
——typeAlias
——package
4、typeHandlers(类型处理器)
5、objectFactory(对象工厂)
6、plugins(插件)
7、environments(环境集合属性对象)
——environment(环境子属性对象)
————transactionManager(事务管理)
————dataSource(数据源)
——————property
8、databaseIdProvider(数据库厂商标识)
9、mappers(映射器)
——mapper
——package
3、properties说明
(1)作用:用来加载项目中的其他配置文件
(2)属性重名下的覆盖情况:在 properties 元素体内指定的属性首先被读取。
然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
最后读取作为方法参数传递的属性,并覆盖已读取的同名属性
4、typeAliases说明
(1)作用:只是用来减少类完全限定名的冗余(在其他mapper.xml文件中,就可以用别名了)
(2) 使用方法:
5、mappers说明
(1)作用:加载mapper.xml文件(告诉MyBatis 去哪里找映射文件)
(2)使用方法: