3.1基础拓展
3.1.1:OGNL表达式
前面我一直在写#{id},#{name},#{age}等语句,每次都会有这么一个#和{},此处就讲解他的作用。
对象–图形导航语言:
可以存取对象的属性和调用对象的方法,通过OGNL的表达式迭代出整个对象的结构图。
OGNL的语法: #{}
employee
id:1,
age:17,
depat:Department类型
id:1,
name:开发部
#{id} 1
#{age} 17
#{depat.name} 开发部
从上述就可以看到,我们#{id}就是从对象的getter方法中进行获取对象属性的值。
3.1.2抽取Mybatis的工具类:
可以看到在前面在方法中写了很多重复的代码,本质就是想获取一个SqlSession对象而已,没有必要每次都重新写,直接封装好了,返回过来就行。
符合重构的思想。
public class MyBatisUtil {
private static SqlSessionFactory factory;
priavate MyBatisUtil (){}
static {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 返回SqlSession对象
*
* @return SqlSession对象
*/
public static SqlSession getSession() {
//传递true表示默认自动提交事务
return factory.openSession(true);
}
}
写完之后测试一下:
//查询单条数据
@Test
void selectOne() {
SqlSession session = MyBatisUtil.getSession();
//4.执行查询方法
//参数1:映射文件中namespace标签名称+id名称
//参数2:需要传递的参数
Student student = session.selectOne("com.mybatis.dmomain.Student.selectone", 2L);
//5.关闭资源
session.close();
System.out.println(student);
}
3.1.3typeAlias
该属性可以用来给实体对象起别名,就好比每个人都有一个小名字一样。
首先来看个问题:
我红色圈起来的地方,每次都要写类的全限定名,也是比较烦人的,若是权限定名很长则需要写的也很长,此时就可以使用简写的方式。 其实也就是在查询的时候需要用到这个返回类型。
使用:
需要在全局配置文件(此处代指上面的mybatis-config.xml文件),进行配置.
配置方式也有三种,此处都来介绍下:
配置别名:
<typeAliases>
//方式1,为每个单独的类配置别名
<typeAlias type="com.mybatis.dmomain.Student" alias="student"/>
// 方式2,为整个包下面的全部类配置别名,别名默认是类名首字母小写
<package name="com.mybatis.dmomain"/>
</typeAliases>
//方式3:贴注解:@Alias("ssss")
@Alias("ssss")
public class Student {
private Long id;
private String name;
private Integer age;
}
注: 应该避免使用贴注解的方式,别名默认myBatis中是不区分大写写的。
在select中可以简单的引用一下就可以了。
还有一些系统自带的别名:
1.基本数据类型的别名在类型前面加_
例如:int ----_int long — _long
2.包装数据类型的别名将首字母小写。
例如:Integer --integer Long-- long
3.集合类型别名也将首字母小写。
例如:List list
ArrayList arraylist
需要用到可以到他官网去查询下。
3.1.4Properties属性
属性配置,此处需要在全局配置文件中进行配置(此处代指mybatis-config.xml)。
配置的文件上面进行申明,下面进行引用。
此时你会发现这样使用的话并没有什么太大的用处,只是将内容提前了一些,看起来更加清晰一点而已,当然,此处肯定不是为了讲解这个方式,我们需要的是从以.properties扩展名结尾的文件中去进行加载他。
<properties resource="db.properties"/>
在mybatis-config.xml文件中进行引用,这种方式才是比较推荐的,也是实施人员最喜欢看的,还有一个url属性,表示可以从网络或者本地磁盘进行加载文件。
3.1.5 resultMap
翻译过来的意思就是结果集映射,首先演示下为什么需要结果集映射,先来演示这个问题,然后再通过结果集映射把该问题解决掉。
此处我们就先来执行一个查询操作:
<select id="selectone" resultType="com.mybatis.dmomain.Student">
SELECT _id,_name,_age FROM student WHERE _id=#{id}
</select>
//查询单条数据
@Test
void selectOne() {
SqlSession session = MyBatisUtil.getSession();
//4.执行查询方法
//参数1:映射文件中namespace标签名称+id名称
//参数2:需要传递的参数
Student student = session.selectOne("com.mybatis.dmomain.Student.selectone", 2L);
//5.关闭资源
session.close();
System.out.println(student);
}
可以发现此时没有任何数据,其实是查询到了,是在封装的时候出问题了,所以在一开始的时候我说此处暂时先把对象的属性名和数据库的字段名保持一致。
仔细看一下命令行查询返回的结果集,字段名和我们的实体类对象的属性名不一样,所以他就没法正确的进行封装了。
配置完了我们再来查询一下:
3.2Mapper接口原理和使用
3.2.1为什么使用?
首先我们来看一下之前写的代码,情景重现下:
我们之前的查询操作是这样的,接下来就通过这个查询代码分析下存在的问题。
1.需要使用namespace命名空间加上id去查询,从一个字符串中就可以体现出,这样很容易写错,系统也不去检查,只有在程序运行的时候才能发现。
2.传入的参数2,就是限定条件,系统也不会去检查(底层设计的就是Object对象),也只有在运行的时候才能发现。
3.代码重复,我们在获取连接对象,关闭资源,都是重复的,只有具体的增删改查操作不一致。
3.2.2如何使用?
上面简单的分析下采用以往的方式所存在的问题,那么接下来肯定就要解决这个问题了:
首先定义一个接口,代码如下:
在mapper的xml文件中namespace中名称就应该用接口的全限定名。
在mapper的xml文件中的id应该对应接口中的方法名。
最后不要忘了再全局配置文件中:
配置一下
上述代码写完了,接下来进行测试:
可以看出来运行和结果也是没问题的,那么来简单分析下:
首先调用getMapper()方法传递一个EmployeeMapper的字节码对象,然后获取到EmployeMapper接口的全限定名,不就是可以得到前面的namespace的字符串吗?
然后再调用他的方法,也就是拼凑成了一开始selectOne(String string ,Object object)方法中的第一个参数,这样就很容易理解了。
底层实现:
使用了一种动态代理的设计模型,不需要掌握,知道就可以。
动态代理就不进入深入讲解了。
补充:
在上面增删改的接口方法上面可以使用返回值,Long ,Integer,Boolean包装类型和基本类型都可以,mybatis会自动返回,比如Long会返回受影响的行数,Boolean会去判断如果影响的行数>0则回返回true。