【1】mybatis在底层通过动态代理创建持久层对应的实现类应该是什么样的:
创建的实现类应该是这样的:
public class UserMapperImpl implements UserMapper {
private SqlSession sqlSession;
public UserMapperImpl(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
/**
* 查询所有的用户数据
* @return
*/
public List<User> getUserList() {
//读取mapper文件,根据全局标识来映射到对应的sql
List<User> userList = sqlSession.selectList("com.ygkj.mapper.UserMapper.getUserList");
return userList;
}
}
此时测试类中就不需要动态代理了,而是直接创建实现类对象,进行查询
更改为:
【2】sqlSession.getMapper是怎么代理的?
getMapper方法底层有个代理工厂类:MapperProxyFactory.class
其中参数为mapperProxy的newInstance方法中,Proxy.newProxyInstance的第二个参数应该是目标类实现的接口,由于其本身就是接口,所以采用new Class[]{this.mapperInterface}
的写法。mybatis底层是为接口做代理,所以目标类就是接口本身。
对代理过程进行模拟:
/**
* 返回值是代理对象:为持久层接口做代理
*/
public Object getProxy(){
return Proxy.newProxyInstance(UserMapper.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用目标方法,接口没有实例,但接口可以创建匿名内部类对象
Object invoke = method.invoke(new UserMapper() {
//在这个方法中需要用sqlSession去xml中映射sql语句
public List<User> getUserList() {
//读取mapper文件,根据全局标识来映射到对应的sql
List<User> userList = sqlSession.selectList("com.jy.mapper.UserMapper.getUserList");
return userList;
}
}, args);
return invoke;
}
});
}
【3】用mybatis对表进行增删改查需注意的点
(1)表中字段名与实体类属性名不一致如何解决?例如表中字段名为e_name,属性名遵循驼峰命名法命名为eName,此时如何解决?
解决方案一(不推荐):在sql语句中给字段名起别名,例如查询表中所有数据select eid,e_name as eName ,age from test04
,缺点是其他不需要起别名的字段也要写出来。
解决方案二:通过mybatis提供的resultMap标签给表中字段和实体属性建立映射关系。
resultMap :建立起实体字段和表字段的对应关系
<resultMap id="empVo" type="com.jy.pojo.Emp">
<!--匹配主键字段-->
<id property="eid" column="eid"></id>
<!--匹配非主键字段-->
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="salary" column="salary"></result>
<result property="birthday" column="birthday"></result>
</resultMap>
此时映射关系已经建立,在select标签中就不写resultType
,而是写resultMap
标签及其全局标识id
(2)使用的方法有参数时,使用parameterType
,即参数类型,如果是基本数据类型,则是什么就些什么,如果是引用数据类型,且是java.lang
包中数据类型,可以直接写类名,例如String,可以写java.lang.String
,也可以写String/string
,甚至可以写sTring等
,其他类型则为参数的全类名。
OGM表达式:#{} 可以取到实体中某一个字段的值,在执行sql的时候,可以防止sql注入
PS:执行增删改操作时,需要提交事务
/**
* @After 会在所有的测试单元执行之后执行
*/
@After
public void mybatisAfter(){
sqlSession.commit();
try {
resourceAsStream.close();
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
(3)SqlSession用途主要有两种
①. 获取对应的Mapper,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果。
②. 直接使用SqlSession,通过命名信息去执行SQL返回结果,该方式是IBatis版本留下的,SqlSession通过Update、Select、Insert、Delete等方法操作。
PS:我们通常是通过Mapper来调用方法操作数据,但通过sqlSession调用delete方法进行也是可以的,如int i = sqlSession.delete("com.jy.mapper.EmpMapper.deleteEmpById", 5);
因为通过Mapper映射找到对应sql执行,其底层也是使用的IBatis中SqlSession通过Update、Select、Insert、Delete等方法操作。但MyBatis更建议使用Mapper,因为这更优雅。
(4)模糊查询
方式一:OGM表达式不支持字符串拼接,所以如果使用OGM表达式,模糊查询的双%写在参数中,OGM表达式花括号中值可以任意写。
方式二:使用支持字符串拼接的el表达式,但表达式内容必须是value