学校的考试也考的差不多了,就剩一个单片机了。昨天下午开始学习MyBatis,到现在差不多一天的时间,一遍看视频,一遍跟着敲一遍,再写一下博客。三步走战略,感觉还挺不错的!学到了不少东西,下面是自己肝的博客,主要得配置一些东西,感觉还是把这些记录下来,以后也能用得到。
首先我们要会建立一个maven工程,不会的小伙伴可以参考我以前写的这篇文章:maven配置使用,这个后面还介绍了Tomcat7的配置,接下来的MyBatis学习并不会用到它,所以看到3.2就行了,能建一个maven工程就可以了。
这篇博客总结的主要内容如下:
- 了解软件的三层架构,并明白为什么要学习MyBatis框架
- 建立maven项目,从零开始一步一步把MyBatis环境搭起来,并完成一个简单的查询sql操作
- 完成查询之后,举一反三,完成一个简单的插入sql操作
- MyBatis设置打印日志、一些工具类的介绍、用idea创建MyBatis的配置文件模板
- 使用MyBatis的动态代理机制简化编程
- MyBatis的sql传参
- 传参时 $ 和 # 的区别
- 动态sql相关
- 分页插件使用
当然自己也就学了一天,所以也并没有多么深入,后续会继续写,小伙伴如果有问题或者发现有什么不对的地方,欢迎与我进行联系。
软件开发常用三层架构
- 界面层(Spring MVC框架):表示层、视图层,主要功能是接受用户的数据,显示请求的处理结果。
- 业务逻辑层(Spring框架):接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
- 数据访问层(MyBatis框架):与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。
三层的处理请求的交互
- 用户—> 界面层—>业务逻辑层—>数据访问层—>DB数据库
准备工作及要求
我的本机mysql环境:springdb数据库内创建一个student表,里面有两组数据。
小伙伴们可以用自己的sql可视化工具创建这个表,并添加两条数据即可。
新建一个maven项目
在src目录下,在默认的main文件夹下,添加java和resources两个文件夹,并分别将其标记为Sources Boot
和Resources Boot文件,在java文件夹中创建我们的包,如我的是cn.gs。
具体配置
先把步骤贴上面,我们根据这几个步骤做就可以
1 | 1.mysql新建student表 |
mysql中插入学生表,已完成
maven的pom.xml配置文件中,依赖项中加入mybatis和mysql驱动包,并在编译build里面加入扫描到.xml的配置。pom.xml文件如下
可能直接用这上面的依赖项的版本会提示找不到,小伙伴们要根据直接的maven仓库自己去选择自己有的
1 |
|
- 在cn.gs下创建一个domain包,包下面创建一个Student类
1 | public class Student { |
- 在cn.gs下创建一个dao包,包下面创建一个StudentDao接口
1 | public interface StudentDao { |
创建mybatis的配置文件,叫做sql映射文件,文件名与接口文件名一样
即在dao包下创建StudentDao.xml文件
1 |
|
- 在resources目录下创建mybatis.xml作为主配置文件,里面定义连接的参数、配置等
1 |
|
- 在cn.gs下面创建一个APP类,完成测试
1 | public class App |
这样我们的MyBatis就快速入门了,这个过程确实会报不少错,但我们一定不要放弃,环境的配置虽然挺麻烦,但是如果这点问题都不去自己解决,那谈什么nb的技术岂不是天方夜谭了!加油!
用MyBatis简单插入一条sql数据
前面我们学会了MyBatis的配置和简单使用,查询了sql的Student表数据,这次我们用它向Student表插入一条学生信息。
在StudentDao类中新添加一条方法:
public int insertStudent(Student student);
在StudentDao.xml配置文件的mapper中新添加一条insert项
1
2
3<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
括号中的 #{xx} 表示函数传的参数student的对应值,就是这样的写法,会用即可。
在测试文件中,要把将要执行的sql语句的表示修改一下,再用SqlSession的insertStudent方法执行,最后还要设置一下提交事务操作。
1
2
3String sqlId = "cn.gs.dao.StudentDao" + "." + "insertStudent";//插入方法
int num = sqlSession.insert(sqlId, student);//执行,返回改变的行数
sqlSession.commit();//提交事务
MyBatis设置打印日志
在MyBatis的主配置文件mybatis.xml中的configuration内添加一个setting即可
1 | <!--设置输出日志--> |
MyBatis主要类的介绍
Resources: mybatis中的一个类, 负责读取主配置文件
1
InputStream in = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactoryBuilder : 创建SqlSessionFactory对象
1
2
3SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);SqlSessionFactory : 重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。在整个项目中,有一个就够用了。
1
2
3
4
5
6
7SqlSessionFactory: 接口,接口实现类: DefaultSqlSessionFactory
SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();
openSession()方法说明:
1. openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
2. openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
openSession(false) 非自动提交事务的SqlSession对象SqlSession:
1
2
3
4
5SqlSession接口 :定义了操作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
SqlSession接口的实现类DefaultSqlSession。
使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。
MyBatis工具类使用
在utils包下创建一个MyBatisUtil类,作为MyBatis的工具类,它会返回一个SqlSession对象
1 | public class MyBatisUtil { |
测试类中创建一个方法,使用这个测试类,用的时候直接通过类名加方法名获取SqlSession对象,然后定义sql的ID标识字符串,将其装载在sqlSession对象里执行即可。
1 |
|
创建MyBatis的mapper和配置文件模板
创建MyBatis的配置文件模板
File –> Settings –> Editor –> File and Code Templates –> file选项,点击 + 创建新的模板
Name填入 mybatis-config,Extension填入 xml,页面格式写入以下内容,点击OK即可
1 |
|
创建MyBatis的mapper模板
File –> Settings –> Editor –> File and Code Templates –> file选项,点击 + 创建新的模板
Name填入 mybatis-mapper,Extension填入 xml,页面格式写入以下内容,点击OK即可
1 |
|
使用MyBatis的动态代理机制
使用MyBatis的动态代理机制,使用SQLSession.getMapper(dao接口)
getMapper能获取dao接口对应的实现类对象,这样获取的dao类就能执行接口中相对应的方法了。
1 |
|
如果要执行插入操作同样的道理,执行dao的insertStudent方法即可。
MyBatis的sql传参
传递一个简单类型的参数
在StudentDao接口中添加方法
1
Student selectStudentById(Integer id);//根据id查询,返回Student对象
在StudentDao.xml接口中添加对应的select
1
2
3<select id="selectStudentById" resultType="cn.gs.domain.Student">
select id,name,email,age from Student where id = #{id}
</select>测试
1
2
3
4
5
6
7
public void selectByIdTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.selectStudentById(1001);
System.out.println(student);
}
传递多个简单类型的参数(使用命名参数)
在StudentDao接口中添加方法
1
2
3//传递多个参数,命名参数,在形参定义的前面加入 @Param("自定义参数名称")
List<Student> selectMultiParam(@Param("myname") String name,
@Param("myage") Integer age);在StudentDao.xml接口中添加对应的select
1
2
3<select id="selectMultiParam" resultType="cn.gs.domain.Student">
select id,name,email,age from Student where name = #{myname} or age = #{myage}
</select>测试
1
2
3
4
5
6
7
public void selectMultiTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> students = mapper.selectMultiParam("zhangsan", 22);
System.out.println(students);
}
传递多个简单类型的参数(使用对象)
和上一个一样,我们传name和age两个参数来进行查询,我们可以把这两个参数封装为一个对象,然后直接用 #{xx} 来实现sql查询即可
1
2
3
4
5
6// 在vo包下面创建一个QueryParam对象,封装name和age成员变量
public class QueryParam {
private String paramName;
private Integer paramAge;
....;//实现其getter/setter,toString()方法
}在StudentDao接口中添加方法
1
2//用对象来传递多个参数
List<Student> selectMultiObject(QueryParam queryParam);在StudentDao.xml接口中添加对应的select
1
2
3<select id="selectMultiObject" resultType="cn.gs.domain.Student">
select id,name,email,age from Student where name = #{paramName} or age = #{paramAge}
</select>测试
1
2
3
4
5
6
7
8
9
10
public void selectMultiObjectTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
QueryParam queryParam = new QueryParam();
queryParam.setParamName("zhangsan");
queryParam.setParamAge(22);
List<Student> students = mapper.selectMultiObject(queryParam);
System.out.println(students);
}当然我们也可以选择用原有的Student类来作为传参对象,它本来就有name和age成员变量,这样也是可以的!
传递多个简单类型的参数(按位置,了解即可)
在StudentDao接口中添加方法
1
2//传递多个参数,按位置
List<Student> selectMultiPosition(String name,Integer age);在StudentDao.xml接口中添加对应的select
1
2
3<select id="selectMultiPosition" resultType="cn.gs.domain.Student">
select id,name,email,age from Student where name = #{arg0} or age = #{arg1}
</select>#{arg0} 和 #{arg0} 表示参数位置:第一个参数和第二个参数
测试
1
2
3
4
5
6
7
public void selectMultiPositionTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> students = mapper.selectMultiPosition("zhangsan",22);
System.out.println(students);
}
$ 和
前面我们传参时候在StudentDao.xml中,用的都是 #{} ,进行参数传递,用 ${} 其实也可以,但是会有问题。
那么这两个东西有什么区别呢?我们先把上面传递一个简单的参数用${}来替换一下,看看有什么区别?
还是原来的三步,只不过换了一下名字,在把mapper文件中那条select中的 #{} 换成了 ${} 即可
在StudentDao接口中添加方法
1
2//用${}传递一个参数
Student selectStudentBy$("id") Integer id); (在StudentDao.xml接口中添加对应的select
1
2
3<select id="selectStudentBy$" resultType="cn.gs.domain.Student">
select id,name,email,age from Student where id = ${id}
</select>测试
1
2
3
4
5
6
7
public void selectStudentByIdWith$Test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.selectStudentBy$(1001);
System.out.println(student);
}
观察输出的结果,发现可以呀,没问题,还是能查询出张三同学。
但是其实打印的日志不太一样,我把两张图片放出来,我们且看一看。
直接上结论:
- #{}:是以预编译的形式,将参数设置到sql语句中;能防止sql注入
- ${}:取出的值直接拼装在sql语句中;会有安全问题(sql注入)
面试题:# 和 $区别
1. **#使用 ?在sql语句中做站位的,使用PreparedStatement执行sql,效率高**
2. **#能够避免sql注入,更安全。**
3. **$不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低**
4. **$有sql注入的风险,缺乏安全性。**
5. **$:可以替换表名或者列名**
例:用${}进行排序
在StudentDao接口中添加方法
1
List<Student> selectStudentsSortBy$("option")String option); (
在StudentDao.xml接口中添加对应的select
1
2
3<select id="selectStudentsSortBy$" resultType="cn.gs.domain.Student">
select id,name,email,age from Student order by ${option}
</select>测试
1
2
3
4
5
6
7
public void selectStudentsSortBy$Test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> students = mapper.selectStudentsSortBy$("name");
System.out.println(students);
}
动态sql
在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等 符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。
实体符号表:
< | 小于 | < |
---|---|---|
> | 大于 | $gt; |
<= | 小于等于 | $lt;= |
>= | 大于等于 | $gt;= |
if
接口方法
1 | List<Student> selectStudentIf(Student student); |
mapper文件
1 | <select id="selectStudentIf" resultType="cn.gs.domain.Student"> |
测试方法
1 |
|
where
接口方法
1 | List<Student> selectStudentWhere(Student student); |
mapper文件
1 | <select id="selectStudentWhere" resultType="cn.gs.domain.Student"> |
测试方法
1 |
|
foreach
➢ collection 表示要遍历的集合类型, list ,array 等。
➢ open、close、separator 为对遍历内容的 SQL 拼接。
语法:
1 | <foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员" separator="集合成员之间的分隔符">#{item 的值}</foreach> |
需求:查询学生id为:1001、1002、1003
接口方法
1 | //动态sql,foreach |
mapper文件
1 | <select id="selectStudentForeach" resultType="cn.gs.domain.Student"> |
测试方法
1 |
|
代码片段
接口方法
1 | List<Student> selectStudentSqlFragment(List<Integer> list); |
mapper文件
1 | <sql id="selectSql"> |
测试方法
1 |
|
Mybatis 通用分页插件——PageHelper
实现步骤
Maven的xml配置文件加入依赖项
1 | <dependency> |
mybatis.xml中配置插件
1 | <!--配置分页插件--> |
用PageHelper 对象使用插件
查询语句之前调用 PageHelper.startPage 静态方法。 除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。 在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个 方法后的第一个 MyBatis 查询方法会被进行分页。
1 |
|