学习这个框架的目的?
代替JDBC,更快速地开发持久层代码,是一个持久层框架。
JDBC有存在什么问题?
1.需要考虑不同数据库之间的方言差异,比如Mysql和Oracle的分页查询,导致平台移植性差,如果要解决这个问题,相同的业务需要开发不同版本的JDBC代码——恶心你
2.JDBC的开发门槛高,要求开发人员的基础知识必须过硬才能发挥出JDBC的性能
连接池需要开发人员管理和配置:因为Connection会话的频繁建立或销毁,这一过程
是最损耗性能的,后来有了连接池的概念,在一个池子里,事先创建好多个Connection,用户用的时候,拿,用完之后,不关,换回去,这样就避免建立和销毁的过程了,但是,需要这个连接池需要开发人员来管理和配置,比如有的人没有经验,一直在池子里创建Connection,忘限制数量了,会有什么结果?堆溢出,服务器挂了
事务需要自己加。容易忘记写
缓存需要自己配,比如查询一条数据,如果多次查询,导致多次访问数据库,造成性能下降,所以引出了缓存的概念,先去缓存查,再去数据库查,减少了数据库的访问次数。但是缓存的配置是需要根据具体的并发访问量和业务场景,需要一定的工作经验
3.JDBC不是面向对象的开发
4.用JDBC查询得到的结果集,最后要封装到javabean里,这个封装工作得自己做。麻烦
5.JDBC是写死在代码里,维护和修改需要改动源代码。
6.JDBC实现关联对象查询时,代码很难写。
Mybatis框架针对上述问题,都解决了。
1.它是半ORM框架,既有面向对象的思想,又是基于sql的,所以叫半ORM框架。
2.它能自动的将数据库查询的结果集封装到javabean里,所以又叫半自动ORM框架。
3.连接池、事务、缓存都帮你做。
4.sql语句不是写在代码里,而是都写在xml文件里,优化和维护sql语句很方便。
5.有一套比较完善的关联对象映射机制,代码很好写。
Mybatis框架结构图
需求说明:在我的mybatis数据库中,有一张user_c表,现在利用Mybatis框架,来做查询,把所有的用户信息都查出来,并将结果集自动封装到对应的javabean里。
开发步骤:
1.创建一个java工程
2.引入依赖jar包
3.数据库建表,填充数据
4.根据表信息,建立对应的javabean
5.在映射文件里写sql语句
6.配置核心配置文件sqlMapCongfig.xml,(配置数据源、加载映射文件)
7.开发持久层(根据核心配置文件创建SqlSessionFactory,创建SqlSession对象,然后执行增删改查等方法)
知识点
1.依赖的jar包
asm-3.3.1.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
mybatis-3.2.2.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
2.数据库建表语句
CREATE TABLE `user_c` (
`id` varchar(40) NOT NULL,
`name` varchar(30) default NULL,
`age` int(11) default NULL,
`address` varchar(200) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user_c`(`id`,`name`,`age`,`address`) values ('1','夏言',73,'桂州村'),('2','严嵩',87,'分宜县城介桥村'),('3','徐阶',80,'明松江府华亭县'),('4','高拱',66,'河南省新郑市高老庄村'),('5','张居正',58,'江陵');
3.核心文件的配置
<environments default="mybatis"> //设置默认用的数据库,本例中是mybatis
<environment id="mybatis">
<transactionManager type="JDBC" /> //设置事务策略,一般用JDBC
<dataSource type="POOLED"> //设置数据源策略,POOLED 池化的
<property name="driver" value="com.mysql.jdbc.Driver" /> //设置数据库的驱动,本例用的是Mysql
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="admin" />
dataSource>
environment>
environments>
<mappers>
<mapper resource="dao/UserMapper.xml" />
mappers>
4.用Mybatis实现查询所有
Xml的代码:
<mapper namespace="pojo.UserMapper">
<select id="findAll" resultType="pojo.User">
select * from user_c
select>
mapper>
注意:
1.nameapce的作用:用来标识映射文件的
2.id的作用:用来标识sql语句的
3.resultType的作用:用来告诉Mybatis把结果集封装到哪个类型的javabean里
持久层的代码:
@Test
public void TestFindAll() throws IOException{
//1.根据核心配置文件创建SqlSessionFactory工厂类
//2.根据工厂类来产生SqlSession对象
//3.调用SqlSession对象身上的方法,比如CRUD
InputStream is=Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
System.out.println(factory);
SqlSession session=factory.openSession();
List<User> list=session.selectList("pojo.UserMapper.findAll");
for(User u:list){
System.out.println(u);
}
注意:
1.获取文件流的操作,一定要用Mybatis提供的:Resources.getResourceAsStream(“sqlMapConfig.xml”);
2.session.selectList(“命名空间.sql的ID名”),执行sql语句并自动封装,本例中得到的数据结构是List
注意,如果想在Console控制台看Mybatis的sql语句,需要引入Log4j.properties
属性文件
1.新增
Xml代码:
<select id="insert">
insert into user_c (id,name,age,address)values('7','jary',23,'泰坦尼克')
select>
或: 用<insert>标签更直观,
<insert id="insert">
insert into user_c (id,name,age,address)values('7','jary',23,'泰坦尼克')
insert>
持久层代码:
public void testInsert(){
SqlSession session=factory.openSession();
session.insert("pojo.UserMapper.insert");
session.commit();
}
知识点:
1.如果是新增,调用session.insert("")方法
2.别忘了加事务,调用session.commit()
2.通过传参来实现新增
Xml代码:
<insert id="insertByGet" parameterType="pojo.User">
insert into user_c (id,name,age,address)values(#{id},#{name},#{age},#{address})
insert>
知识点:
1.parameterType配置的属性:传参所使用的数据类型
2.parameterMap是一个过时的方法,禁用
3.#{参数名},Mybatis的参数解析表达式,工作原理:根据parameter的类型,本例中是User,拿参数名和User的私有属性名进行匹配和查找,注意:名称要严格对应,包括大小写。
4.#{}的作用可以根据参数值的类型自动处理,如果String类型,就加’ ‘,如果是整形,就直接数字。
5.#{}实际调用的JDBC prepareStatement,它和Statement的区别:
第一是前者具有预编译功能,效率高,因为sql语句说白了拆串,如果放在执行的时候进行拆串的话,影响效率,所以预编译提高效率。
第二防sql注入攻击,注入攻击的方式很多,其中之一就是在’上做文章。比如:select * from user where password=’用户提交的密码’, 黑客:1 ‘or’ 1’=’1 ,那实际执行的就是:
select * from user where password=’1 ‘ or ’ 1’=’1’。
持久层代码:
public void testInsertByGet(){
SqlSession session=factory.openSession();
User user=new User();
user.setId("8");
user.setName("Rod Johnson");
user.setAge(1000);
user.setAddress("澳大利亚");
session.insert("pojo.UserMapper.insertByGet", user);
session.commit();
}
知识点:
1.调用session.insert(str,obect),把User对象传过去。
3.更新
Xml代码:
<update id="update">
update user_c set name="万历皇帝" where id='5'
update>
持久层代码:
public void testUpdate(){
SqlSession session=factory.openSession();
session.update("pojo.UserMapper.update");
session.commit();
}
知识点:
1.调用session.update()实现更新
4.通过传参实现更新
Xml代码:
<update id="updateByGet" parameterType="string">
update user_c set name=#{name} where id='6'
update>
知识点:
1.当传递的参数只有一个时,parameterType可以设置成string。
持久层代码:
public void testUpdateByGet(){
SqlSession session=factory.openSession();
String name="jary";
session.update("pojo.UserMapper.updateByGet", name);
session.commit();
}
5.删除
Xml代码:
<delete id="delete">
delete from user_c where id='6'
delete>
持久层代码:
public void testDelete(){
SqlSession session=factory.openSession();
session.delete("pojo.UserMapper.delete");
session.commit();
}
6.批量删除
Xml代码:
<delete id="batchDelete" parameterType="string">
delete from user_c where id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
foreach>
delete>
知识点:
1.批量删除时,parameterType类型为sql语句里in()的参数类型,此处id是字符串,所以是string类型。
2.标签
collection:array(表示用的是数组传递的参数,array是固定写法)
Item:起个名来标识数组遍历时的每个元素,因为后期我们要根据这个名字来操作这个参数。
Open:拼串用的,拼的是开头的字符,这里是(
Close:拼的是结尾的字符,这里是)
Separator:指定分隔符,这里是,
如何解析参数:#{item的名字}
持久层代码:
public void testBatchDelete(){
SqlSession session=factory.openSession();
String [] ids=new String[]{"6","7","8"};
session.delete("pojo.UserMapper.batchDelete", ids);
session.commit();
}
知识点:
封装参数用的是数组,通过调用session.delete(str,object)把数组传过去。
1.单条件
Xml文件:
<select id="findAllByGet" parameterType="string" resultType="pojo.User">
select * from user_c where id=#{id}
select>
持久层:
public void testFindAllByGet(){
SqlSession session=factory.openSession();
List<User> list=session.selectList("pojo.UserMapper.findAllByGet","7");
}
知识点:
1.虽然返回值是单个User对象,但是也可以selectList()方法得到一个只包含一个对象的集合,继而取得这个对象。
public void testFindAllByGet(){
SqlSession session=factory.openSession();
User user=session.selectOne("pojo.UserMapper.findAllByGet", "7");
}
知识点:
1.如果想直接拿到返回的单个对象,则可以调用session.selectOne(str,object)
2.多条件查询 < 的问题
Xml文件:
<select id="findByCondition" parameterType="map" resultType="pojo.User">
select * from user_c where address like #{address} and age>#{minAge} and age #{maxAge}
select>
知识点:
1.当多条件查询时,如何解析条件参数是最关键的问题,对于一般情况可以pojo对象来传参,但是对于含年龄段的查询时,则用Map来传参。parameterType=”map”
2.Xml文件里 < 符号的转义问题,如果不进行处理,则默认为Xml的<>没有闭合。所以用来进行转换。 还可以用<
3.参数解析的原理:从map里根据key来找value,这种方式最灵活,是常用的手段。但是需要注意解析参数名和Key值保持一致。
持久层:
public void testFindByCondition(){
SqlSession session=factory.openSession();
Map map=new HashMap<>();
map.put("address", "%村%");
map.put("minAge", 60);
map.put("maxAge", 80);
List<User> list=session.selectList("pojo.UserMapper.findByCondition",map);
System.out.println(list.size());
}
知识点:
通过map来封装参数值,然后调用session.selectList(str,object)来传递map。
3.排序
Xml文件:
<select id="order" parameterType="map" resultType="pojo.User">
select * from user_c ORDER BY ${orderValue}
select>
知识点:
当排序的时候,解析参数需要注意,因为#{}会把String的参数加’ ‘,这样拼装后的sql语句就变成了… Order by ‘参数值’ ,所以虽然可以排序,但是意义完全不同,所以结果肯定错误。解决办法:用${}来做,它的工作原理是:直接解析,不加’ ’。
持久层:
public void testOrderBy(){
SqlSession session=factory.openSession();
Map map=new HashMap();
map.put("orderValue", "age");
List<User> list=session.selectList("pojo.UserMapper.order",map);
for(User user:list){
System.out.println(user);
}
}
1.带条件的动态查询
Xml文件:
<select id="findByConditions" parameterType="map" resultType="pojo.User">
select * from user_c
<where>
<if test="address!=null">address like #{address}if>
<if test="minAge!=null">and age>#{minAge}if>
<if test="maxAge!=null">and age#{maxAge}if>
where>
select>
知识点:
1.对于多条件查询,有时候查询的条件会根据具体场景或增或减,所以会产生很多情况啊,但是我们不可能一一手写出每一种情况的sql语句,所以,Mybatis针对这种情况,产生了动态Sql的概念。
2.标签的使用,标签里test的作用是写条件,形式:
3.在使用标签时,需要注意 and 关键字,因为如果首提交没有参与拼串,则sql语句会变成 :…where and age>70 那这样的话就错了,所以解决办法:①用where ‘1’=’1’来解决 ②用来解决,这个标签的工作原理:判断并截串,如果有and,并且是紧接着where提交,则截掉。
4.比如对于这个:address like #{address}红色的address和绿色的address注意不是一回事,前者通过Map封装的key值,后者是sql的条件。
持久层:
public void testFindByConditions(){
SqlSession session=factory.openSession();
Map map=new HashMap<>();
map.put("minAge", 70);
map.put("maxAge", 80);
List<User> list=session.selectList("pojo.UserMapper.findByConditions",map);
for(User user:list){
System.out.println(user);
}
}
2.动态更新
Xml文件:
<update id="updateByConditions" parameterType="pojo.User">
update user_c
<set>
<if test="name!=null">name=#{name},if>
<if test="age!=null">age=#{age},if>
<if test="address!=null">address=#{address}if>
set>
where id=#{id}
update>
知识点:
1.对于多字段更新,也可以用标签来实现对条件的控制,但是需要注意:当某一个条件为null时,会出现 ,(逗号)多余的情况,所以这时要用标签,它的工作原理是:就是判断整个sql语句拼完后有没有多余的逗号,有的话删掉。
持久层:
public void testUpdate(){
SqlSession session=factory.openSession();
User user=new User();
user.setId("7");
user.setName("宋江");
session.update("pojo.UserMapper.updateByConditions", user);
session.commit();
}
动态sql的意义
1.写Sql语句更为灵活和通用,尤其从多提交查询和更新可以看出,不用一一的写出每一种可能的情况。
2.性能的提高,Mybatis可以做到单个字段级的优化。比如说更新操作,如果只更新一个name字段,之前的hibernate框架它是把整个对象的所有字段属性都参与进来,而Mybatis则可以灵活的优化sql语句,处处优化,则性能会有显著的提高。
上一篇 54…大数据之旅——java分布式项目15–商品搜索整合,爬虫,Jsoup介绍