本文衔接MyBatis基础学习知识点1,继续对以下两个问题进行探讨
1.dao配置文件主要是用来干什么的?如何进行配置?
2.使用测试方法测试程序运行是如何实现的?每条语句起什么作用?
目录
dao配置文件主要是用来干什么的?如何进行配置?
mapper标签
select标签
insert标签
update标签
delete标签
使用测试方法测试程序运行是如何实现的?每条语句起什么作用?
基础步骤
SqlSessionFactory接口
SqlSession接口
MybatisUtils工具类
实现dao接口
使用代理模式
mybatis的dao代理
理解参数
parameterType
传递一个简单类型参数
传递多个简单类型参数
使用实体类属性传递参数
按照位置传递参数
使用map传参
#占位符与$占位符的区别
封装MyBatis输出结果
resultType
当查询结果为自定义类型时
当查询的结果为简单类型时
当查询结果为Map类型时
resultMap自定义查找结果
有关like查询
dao配置文件主要是用来干什么的?如何进行配置?
我们拿出一个最简单的dao层配置文件进行分析
<?xml version="1.0" encoding="UTF-8" ?>
可以看到配置文件标签体都在http://mybatis.org/dtd/mybatis-3-mapper.dtd的约束下
其中最为核心的就是mapper标签
mapper标签
mapper标签用于配置dao接口的相关映射
namespace属性
用于定义访问sql语句的命名空间,我们在书写最终执行代码的时候可以看到
@Test public void test1() throws IOException { //定义mybatis核心配置文件在classes下的路径 String mybatisPath = "mybatisConfig.xml"; //根据路径获取字节输入流对象 InputStream is = Resources.getResourceAsStream(mybatisPath); //创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //通过SqlSessionFactoryBuilder对象的build方法创建SqlSessionFactory对象 SqlSessionFactory factory = sqlSessionFactoryBuilder.build(is); //通过工厂类的openSession方法获取sql执行对象 SqlSession sqlSession = factory.openSession(); //sql执行对象的selectOne方法 //获取第一个参数,即执行id:由namespace + 、+ SQL语句标签id String id = "com.ling.mybatis.dao.UserDao" + "." + "findUserById"; User user = sqlSession.selectOne(id); System.out.println(user); //关闭sqlSession sqlSession.close(); }
最终sql语句会由SqlSession对象执行,当sql语句执行时需要传入一个字符串,该字符串就时由命名空间和sql语句id构成,如此书写可以让程序更具格式化,层次分明。
namespace的值建议设置为dao接口在src下的全路径名称,为了方便分清结构层次,以及后续工具的使用,作用是参与识别sql语句的作用。
select标签
主要用于书写select相关sql语句
id属性
设置sql语句名称,为了方便分清结构层次,以及后续工具的使用,建议使用对应的方法名称
resultType属性
设置查找到的最终结果的返回值类型,类型需要写src下的全路径名称
例如:
insert标签
主要用于书写insert相关sql语句
id属性
设置sql语句名称,为了方便分清结构层次,以及后续工具的使用,建议使用对应的方法名称
update标签
主要用于书写update相关sql语句
id属性
设置sql语句名称,为了方便分清结构层次,以及后续工具的使用,建议使用对应的方法名称
delete标签
主要用于书写delete相关sql语句
id属性
设置sql语句名称,为了方便分清结构层次,以及后续工具的使用,建议使用对应的方法名称
使用测试方法测试程序运行是如何实现的?每条语句起什么作用?
首先我们使用以下基础执行代码作为例子进行说明
@Test public void test1() throws IOException { //定义mybatis核心配置文件在classes下的路径 String mybatisPath = "mybatisConfig.xml"; //根据路径获取字节输入流对象 InputStream is = Resources.getResourceAsStream(mybatisPath); //创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //通过SqlSessionFactoryBuilder对象的build方法创建SqlSessionFactory对象 SqlSessionFactory factory = sqlSessionFactoryBuilder.build(is); //通过工厂类的openSession方法获取sql执行对象 SqlSession sqlSession = factory.openSession(); //sql执行对象的selectOne方法 //获取第一个参数,即执行id:由namespace + 、+ SQL语句标签id String id = "com.ling.mybatis.dao.UserDao" + "." + "findUserById"; User user = sqlSession.selectOne(id); System.out.println(user); //关闭sqlSession sqlSession.close(); }
基础步骤
第一步:设置中心配置文件的路径
第二步:使用Resources静态方法,将中心配置文件加载进字节输入流
第三步:获取SqlSessionFactoryBuilder对象,该对象的主要任务是创建factory对象
第四步:使用SqlSessionFactoryBuilder对象的build方法,传入字节输入流,解析中心配置文件,初始化数据库连接池,并且获取各个dao配置文件。
第五步:通过SqlSessionFactory对象的openSession方法获取sqlSession执行对象,该对象主要用于sql语句的执行操作。
第六步:定义字符串,锁定需要执行的语句
第七步:执行sql语句
SqlSessionFactory接口 接口作用
SqlSessionFactory接口是sqlSession的工厂接口,主要作用是创建SqlSession对象
SqlSessionFactory功能众多,创建过程较之其他比较缓慢,需要更多的时间和空间,在项目中有一个即可。
接口方法
openSession();获取一个默认的SqlSession对象,默认是需要手动提交事务的
openSession(boolean):boolean参数表示是否自动提交事务
true:创建一个自动提交事务的SqlSession
false:等同于没有参数的openSession
SqlSession接口 接口作用
提供了大量的执行sql语句的方法,线程不安全
针对线程不安全,需要注意使用步骤
使用步骤
1.在方法内部执行sql语句之前,先获取sqlSession对象
2.调用sqlSession方法对象,执行sql语句
3.关闭sqlSession,执行sqlSession的close方法
如此一来,该sqlSession就只在方法内存在,在该方法所在执行的线程空间内存在,这样其他线程就无法获取这条线程内的数据对象。
接口方法selectOne(String,Object):执行返回值只有一行的执行结果,多余一行会执行错误
selectMap(String,Object):执行返回一个map类型的接口
selectList(String,Object):执行返回一个list集合数据
insert(String,Object):执行添加操作
update(String,Object):执行修改操作
delete(String,Object):执行删除操作
commit:执行事务提交操作
rollback:执行事务回滚操作
MybatisUtils工具类
由上文实现步骤我们可以看出,每一次进行数据库操作我们都需要进行以上七步的操作,但是七步操作中有大量的代码冗余,一到五步代码基本大致相同,因此我们可以写构造一个MybatisUtils工具类,专门用于mybatis初始化操作。
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory = null; //通过静态代码块,当类进行加载时赋值 static { String sqlPath = "mybatisConfig.xml"; try { //根据核心配置文件路径获取字节输入流 InputStream resource = Resources.getResourceAsStream(sqlPath); //使用Builder对象的build方法获取factory对象 sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource); } catch (IOException e) { e.printStackTrace(); } } //获取SqlSession对象(不自动提交事务) public static SqlSession getSqlSession(){ //openSession方法中没有参数,则取消自动提交。传入true则打开自动提交 return sqlSessionFactory.openSession(); }}
此时我们简化了前五步步骤,但是第六步简单的字符串拼接和第七步方法的执行还是没有简化,而且我们在使用的过程中发现,接口好像根本没啥作用,接口的方法没有被调用,接口也没有实现类,接口好像白写了?
实现dao接口
按照Javaweb学习阶段三层架构的代码书写习观我们创建impl文件夹,并且于文件夹内部创建dao接口实现类。
public class UserDaoImpl implements UserDao { @Override public List
我们将第六步第七步的操作步骤放到了接口实现类中,这样就完成了整合,当我们需要调用方法进行sql语句操作时,创建dao接口实现类对象,执行其对应的方法即可。
但是对于以上整合方案并不能帮助我们简化程序书写的步骤,只是简单的对数据操作进行了整合操作,我们需要一种可以直接完成数据操作的方法
使用代理模式 mybatis的dao代理
代码书写
getMapper(dao接口的class类)
@Test public void test2() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); userDao.findUserById(1); sqlSession.close(); }
通过sqlSession的getMapper方法获取代理对象,我们在学习Spring框架的Aop增强时学习过了proxy代理模式,主要工作原理是通过反射机制创建目标增强对象的子类,并且在不改变原方法内容的情况下强化方法的参数,内容,返回值。
这里的getMapper方法就是使用代理模式,创建userDao的实现类对象,并且通过类加载器和反射机制获取UserDao的路径名,以及方法名,自动的完成拼接,并且选择合适的sqlSession方法执行增删改查的操作。这里就回收了为什么我们在设置dao层配置文件namespace属性尽量要设置为dao接口src下全路径,为什么sql语句标签id要设置为方法名。
理解参数
通过Java程序把数据传入到mapper文件中的sql语句,这里的参数主要是指dao接口方法中的形参
parameterType
表示参数类型,指定dao方法的形参数据类型。这个形参的数据类型是给mybatis使用。mybatis在给sql语句的参数赋值时使用,我们在jdbc中学习过的防止sql语句注入,使用preparedStatement对象。我们对?内容进行属性值注入时,需要使用对应的setXXX(索引,值)方法进行输入,这里的parameterType就是在选择注入的属性类型。
mybatis可以使用反射机制获取dao接口方法参数类型,因此parameterType可以省略不写
传递一个简单类型参数
简单类型:Java中的基础数据类型
当传递的参数时一个简单类型的参数时,mapper文件使用#{任意字符}获取这个参数值
传递多个简单类型参数
使用@Param注解,用于命名参数,在方法的形参前面使用,定义参数名。这个名称要用于mapper文件中,也就是#{}内的值就是参数命名后的名称
List
使用实体类属性传递参数
方法参数直接传入一个实体类,那么mybatis就会自动解析实体类属性,并且根据属性名称查找配置文件中#{}内的参数名称,如果匹配,那么就赋值。
int insertUser(User user);
按照位置传递参数
按照位置传参,接口中的多个参数就不需要添加@Param注解起别名,只需要在sql语句中使用#{arg索引}就可以指定传入第几个参数
List
使用map传参
map中的key值就对应了#{}中的名称,value值即为注入的值。
List
#占位符与$占位符的区别
#占位符实际上是PrepareStatement编译了sql语句之后对于值的一个注入,而$占位符做的是简单的字符串拼接,也就是使用普通的Statement。
$特点:
1.使用的是Statement对象,执行SQL语句时效率低
2.${}占位符,使用的是字符串拼接的方式,有sql注入的风险,有代码安全性问题
3.${}数据是原样使用的,不会区分数据类型
4.${}常常用作表名或者列名,在能保证数据安全的情况下使用${}
#特点:
1.使用PrepareStatement对象,执行sql语句,效率高。
2.使用PrepareStatement对象,能够避免sql语句注入问题,SQL语句执行更安全
3.#{}常常作为列值使用,位于等号的右侧,#{}位置的值和数据类型有关
封装MyBatis输出结果 resultType
resultType属性:在执行select时使用,作为
resultType:表示结果类型,mysql执行sql语句,得到java对象出现的类型,他的值有两种
1.java类型的全限定名称(我们之前一直使用的)
2.在中心配置文件中设置的别名
别名我在第一篇文章中讲解中心配置文件的时候详细说过,他是在中心配置文件的typeAliases标签内部设置的,如果使用package标签取别名,那么就是整包一起取,如果使用typeAlias标签的话就是一个一个取,具体的优缺点可以看我的第一篇文章。
中心配置文件:
dao层配置文件:
当查询结果为自定义类型时
其实就是我们一直写的以User作为返回值结果,这就是将查询的结果封装到类对象中。
当sql语句查询到数据后,mybatis会根据resultType会根据配置内容使用java反射调用无参构造器创建对象,然后将获取到的结果集对应的key值与对象属性值进行比对,如果属性名称相同就把值注入到对象中。如果查询到多行数据,那么就会创建多个对象,并且将对象存放入list集合中。
User findUserById(Integer id);
当查询的结果为简单类型时
设置resultType直接设置为java中的路径
Integer getSum();
当查询结果为Map类型时
mybatis会将sql语句查询结果以键值对的形式添加到map集合中,但是如果使用map作为返回值,那么该程序执行结果只能有一行查询结果,多了就会报错
Map
resultMap自定义查找结果
使用resultMap可以自定义结果集中属性与对象属性的对应关系,常用于对象属性与查询结果列名不相同的情况。
如何使用:
1.主键名使用id标签,column指定结果集中的列名,property指定类中的属性名。
2.其他列名使用result标签,column指定结果集中的列名,property指定类中的属性名。
3.id属性用于设置该结果集的名称
4.type属性用于指定需要匹配的类
5.select标签中resultMap属性设置为resultMap标签中的id值
List
select标签属性resultMap获取了配置相关信息的resultMap标签唯一名称,通过唯一名称查找到了配置好的resultMap,根据type属性获取返回值类型,并且解析id标签与result标签内容,获取属性值对应关系,最后将查找到的值首先按照对应关系赋值,然后正常赋值。
有关like查询
当查询语句需要使用like
例如:select * from user where name like %zhang%;
第一种:将%zhang%整体作为一个字符串传入
List
@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); List
第二种:在sql语句中按照标准书写,"%" 值 "%" 值... 其中%与值中间必须有空格
List
@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); List