Mybatis的深入
课程介绍
- 回顾mybatis的自定义再分析和环境搭建+完善基于注解的mybatis
- mybatis的CRUD(基于代理dao的方式)
- mybatis的参数深入及结果集的深入
- mybatis基于传统dao的编写方式(编写dao的实现类)--了解
- mybatis中主配置文件的介绍(SqlMapConfig.xml)
- properties标签
- typeAliases标签
- mappers标签
配置基于dao代理的CRUD
配置基于dao代理的CRUD很简单,自己不用写dao的实现类,只需要配置两个地方就可以使用dao进行CRUD操作,前提是mybatis的主配置文件已经写好,这个可以看day01环境配置那里。
- dao接口添加方法
- dao接口对应的映射配置文件添加方法对应的sql语句,还要指明对应方法的参数类型,返回值类型
1. 保存
IUserDao接口添加方法
void saveUser(User user);
-
IUserDao.xml添加
insert
标签:insert
的id
为方法名insert
标签中需要添加参数类型parameterType,因为该方法有参数传入parameterType属性:如果是自己定义的类,需要全限定类名
sql语句需要参数,使用#{value}从形参中按照变量名获取,====================
insert into user(name,address,sex,birthday) values(#{name},#{address},#{sex},#{birthday});
2. 更新
void updateUser(User user);
update user set name=#{name},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id};
3. 删除
void deleteUser(int id);
需要提供
int id
,就给了Integer
,这里只要是能表示出int
类型的都可以,包括int
,INT
等。delete from user where id=#{uid};
4. 根据id查找用户
/** * 根据id查找user * @param id * @return */ User findById(int id);
这里方法有返回值,所以要用
resultType
指明返回类型,自定义对象需要全限定类名,String
之类基本数据类型只要写出那几个字母即可,如string
,int
,double
即可,没有严格要求,后面会讲为什么。同时如果只有一个参数,且是基本类型,则
#{value}
中的value
随便写都可以,不用和形参名对应
5. 返回List的查询所有用户
/** * 查询所有user * @return */ List
findAll(); 这里返回值
resultType
指明为com.chajiu.domain.User
,即泛型的实际类型即可。
6. 模糊查找
/** * 根据名字模糊查询 * @param name * @return */ List
findByName(String name); 此处把
'%王%'
句子放在了形参里,故调用时需要提供参数为:%王%
接下来就可以进行测试。
7. 返回一行一列:查询用户总数
/** * 查询总数 * @return */ int findTotal();
没啥特别,只要指明返回类型即可。
mybatis dao测试
使用dao需要六步:
//1. 读取配置文件,生成字节输入流
//2. 获取SqlSessionFactory对象
//3. 获取SqlSession对象
//4. 获取dao的代理对象
//5. 使用代理对象执行方法
//6. 释放资源
如果在每个方法中都写上这些步骤,显得繁琐。因此把重复的代码抽出包装成方法。
@Before
注解的方法在 @Test
方法执行前执行, @After
注解的方法在其之后执行。故正好用于创建 SqlSession
和释放资源。(这些注解在junit包中)
package com.chajiu.test;
import com.chajiu.dao.IUserDao;
import com.chajiu.domain.User;
import org.apache.ibatis.io.Resources; //注意Resources导包
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisTest {
//将测试方法中需要用到的对象声明为成员变量。
private InputStream in; //未来要关闭
private SqlSession session;//未来要关闭
private IUserDao userDao; //未来要调用接口方法
@Before//用于在测试方法前执行
public void init() throws IOException {
//1. 读取配置文件,生成字节输入流
in= Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 获取SqlSessionFactory对象
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
//3. 获取SqlSession对象
session=factory.openSession();
//4. 获取dao的代理对象
userDao=session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行后执行
public void destroy() throws IOException {
//5.设置手动提交事务
session.commit();
//6. 关闭
session.close();
in.close();
}
//查询所有
@Test
public void testFindAll(){
//5. 执行查询所有
List users=userDao.findAll();
for (User user:users) {
System.out.println(user);
}
}
//保存
@Test
public void testSaveUser(){
User user=new User();
user.setName("mybatis");
user.setAddress("北京市顺义区");
user.setSex("男");
user.setBirthday(new Date());
System.out.println(user);
//5. 执行保存
userDao.saveUser(user);
System.out.println(user);
}
//更新
@Test
public void testupdateUser(){
User user=new User();
user.setName("mybatis_update");
user.setAddress("北京市顺义区");
user.setSex("男");
user.setBirthday(new Date());
user.setId(4);
userDao.updateUser(user);
}
//删除
@Test
public void testDeleteUser(){
userDao.deleteUser(5);
}
//根据id找user
@Test
public void testFindById(){
User user=userDao.findById(2);
System.out.println(user);
}
//根据名字模糊查询
@Test
public void testFindByName(){
List users=userDao.findByName("%y%");
for(User user:users){
System.out.println(user);
}
}
//查询总数
@Test
public void testFindTotal(){
System.out.println(userDao.findTotal());
}
}
mybatis替我们做了什么
- 读取xml配置文件
- 注册驱动
- 数据库的连接
- 事务的开启(SqlSession还是要先自己构造出来)
- 创建dao接口的代理对象(用SqlSession)
- 封装查询结果到对象中
mybatis参数详解
1. parameterType 输入参数类型
可以传递:
简单参数
-
自定义pojo类型
- 使用
#{}
或者${}
指定属性名称=======是的,${}
也可以
- 使用
-
包装类型
-
若包装了多个自定义pojo对象,如何访问其中的属性?
把
#{value}
视为parameterType
的类中的属性,有类QueryVo
包含Userpublic class QueryVo { private User user; //getter //setter }
则通过
#{user.name}
访问user的name属性。即视为拼在输入类型后面。
-
注意:sql语句中的#{value}
value字段必须和实体类中的属性名称对应!!!
OGNL表达式:
- Object Graphic Navigation Language 对象 图 导航 语言
- 它是通过对象的取值方法来获取数据,在写法上把get省略了
- 比如:获取用户名称
- 类中:user.getUserName()
- OGNL:user.userName
- mybatis中为什么不用user.userName,而是直接userName呢?
- 因为在parameterType中已经指明了属性所属的类,因此不用写对象名
2. resultType 结果类型
输出简单类型
-
输出pojo对象
mybatis如何封装查询结果到pojo呢?
第一种方法:表字段名和pojo属性名对应,自动匹配。不对应的匹配不上为null
-
第二种方法:表字段名和pojo属性名不对应时,
-
改sql语句,别的都不用改:
- 优点:执行效率高
select id as userId, name as userName, sex as userSex, address as userAddress, birthday as userBirthday from user
-
或者手动配置查询结果字段和实体类属性的映射关系,返回结果改成
resultMap
:- 优点:方便开发
-
- 输出pojo列表
3. properties
原本properties用于配置连接数据库的四个信息:
现在可以用properties
标签把property
抽出来,原处property
标签的value
用${name}
指向上面的property
:=======必须用 ${}
,不可用 #{}
所以说,
可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置信息:
-
resource属性:常用
- 用于指定配置文件的位置,按照类路径的写法写,并必须存在于类路径下
- 如
- 如
- 用于指定配置文件的位置,按照类路径的写法写,并必须存在于类路径下
-
url属性:
要求 按照url的写法写位置
-
URL:统一资源定位符,他可以唯一标识一个资源的位置
写法:http://localhost:8080/mybatis_demo/demoServlet
协议 主机 端口 URI
- URI:统一资源标识符,在应用中唯一定位一个资源
-
所以使用URL属性可以把配置文件放在任意目录,但是路径写为:
file:///C:/Users/Alice/IdeaProjects/jdbcConfig.properties
使用协议:
file://
端口主机省略,故是
file:///
如
4. typeAliases标签
用于给实体类取别名,方便在parameterType
和 resultType
中使用,不用再写全限定类名了,这就是为什么String
以及基本数据类型不用写全限定类名的原因,他已经默认配好了别名。
使用:凡是要指定全限定类名的地方都可以用,比如parameterType
,resultType
,resultMap
中的type
5. package 标签
刚才typeAliases
中用了package
,这样这个包下的类自动有了别名。
在主配置文件的Mappers
中,也可以用这个package
标签,用于指定dao接口的包,写了这个就不用再写mapper
、resource
以及class
了,他会自己去找xml文件,方便开发。