1.半自动与全自动的区别,MyBatis与Hibrnate的区别:
需要手动编写 sql 来完成,称之为半自动 ORM 映射工具。
查询关联对象或者关联集合对向象时,可以根据对象关系模型直接获取,称为orm的全自动。
他们之间的区别在于sql语句是需要手动编写还是自动获取。
Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
Hibernate属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。
1> MyBatis 把 sql 语句从 Java 源程序中独立出来,放在单独的 XML 文件中编写,给程序的
维护带来了很大便利。
2> MyBatis 封装了底层 JDBC API 的调用细节,并能自动将结果集转换成 Java Bean 对象,
大大简化了 Java 数据库编程的重复工作。
3> 因为 MyBatis 需要程序员自己去编写 sql 语句,程序员可以结合数据库自身的特点灵活
控制 sql 语句,因此能够实现比 Hibernate 等全自动 orm 框架更高的查询效率,能够完成复
杂查询。
hibernate和mybatis对比
1相同之处
Hibernate和mybatis都是属于持久层框架(操作数据库的框架).
操作数据库的底层都是使用的JDBC.
并且都是ORM类型的框架.
通过操作对象,映射操作数据库的表。
2不同之处
映射关系不同:
Hibernate:
实体类对象 =对应=> 数据库的表
对象的属性 =对应=> 表的列
MyBatis:
表dao =对应=> 映射文件
表dao中的方法 =对应=> 映射文件中的sql语句
2.了解orm框架。
对象关系映射简称ORM(Object Relational Mapping)框架采用元数据来描述对象与关系映射的细节,元数据一般采用XML格式,并且存放在专门的对象一映射文件中。简单理解为一种框架的格式。
它是是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。当前ORM框架主要有五种:Hibernate、iBatis、mybatis、JFinal、EclipseLink。
简单来说ORM框架就是连接数据库的桥梁,就是将数据库类型转换成面向对象编程语言的类型,可以理解为“翻译”。
3.动态sql:一对一、一对多、多对多
动态SQL:
sql的内容是变化的, 可以根据条件获取到不同的sql语句。
主要是where部分发生变化。
动态sql的实现, 使用的是mybatis提供的标签。
一对一表查询:
一对一的关系就是:一个商品对应一个商品种类。所以我们创建实体类的时候,可以这么创建:
public class Goods {
private int id;
private int imgId;
private String name;
private String content;
private int status;
private String createTime;
private String updateTime;
private Category category;
}
然后我们在对应的Dao接口方法里定义函数:
public interface GoodCategoryDao {
public List<Goods> findAllGoodsWithCate();
}
书写sql语句:
<select id="findAllGoodsWithCate" resultMap="GoodsWithCate">
select a.*,b.category_name from goods a join category b on a.category_id=b.category_id
</select>
通过category_id 字段相同来建立两个表一一对应的关系。
一对多表查询: 一对多的场景为:一个商品类型对应了多个商品:
所以我们建立实体类可以在商品类型实体类里边添加一个goods集合:
public class Category {
private int categoryId;
private String categoryName;
private List<Goods> goodsList;
}
然后去添加dao接口方法和xml实现方法:
public interface GoodCategoryDao {
public List<Goods> findAllGoodsWithCate();
public List<Category> findAllCateWithGoods();
}
Select方法:
<select id="findAllCateWithGoods" resultMap="CateWithGoods">
select b.*,a.* from goods a right join category b on a.category_id=b.category_id
</select>
动态sql拼接:
<select id="findStudentByCondition" resultType="Student">
select * from student where 1=1
<if test="sName!=null">
and s_name like #{sName}
</if>
<if test="sSex!=null">
and s_sex =#{sSex}
</if>
</select>
多对多:涉及到三张表如下:
sys_role
sys_user
sys_role_user
通过sys_role_user表查询每个用户的职称
主方法:
public List<User> list() {
List<User> userList = userDao.findAll();
for (User u : userList){
Long id = u.getId();
List<Role> roleList = roleDao.findById(id);
u.setRoles(roleList);
}
return userList;
}
dao层 fundAll()
public List<User> findAll() {
return jdbcTemplate.query("select * from sys_user", new BeanPropertyRowMapper<User>(User.class));
}
dao层 findById(id)
public List<Role> findById(Long id) {
List<Role> query = jdbcTemplate.query("select * from sys_user_role ur, sys_role r where ur.roleId = r.id and ur.userId = ?", new BeanPropertyRowMapper<Role>(Role.class), id);
return query;
}
查询结果:
4.mybatis中#与$的区别
#占位符:
1> MyBatis处理 #{ } 占位符,使用的 JDBC 对象是PreparedStatement 对象,执行sql语句的效率更高。
2> 使用PreparedStatement 对象,能够避免 sql 注入,使得sql语句的执行更加安全。
3> #{ } 常常作为列值使用,位于sql语句中等号的右侧;#{ } 位置的值与数据类型是相关的。
4> #传入的参数在SQL中显示为字符串(当成一个字符串),会对自动传入的数据加一个双引号。如下:
select id,name,age from student where id =#{id}
select id,name,age from student where id ="1"
$占位符:
1> MyBatis处理 ${ } 占位符,使用的 JDBC 对象是 Statement 对象,执行sql语句的效率相对于 #{ } 占位符要更低。
2> ${ } 占位符的值,使用的是字符串连接的方式,有 sql 注入的风险,同时也存在代码安全的问题。
3> ${ } 占位符中的数据是原模原样的,不会区分数据类型。
4> ${ } 占位符常用作表名或列名,这里推荐在能保证数据安全的情况下使用 ${ }。
5>$传入的参数在SqL中直接显示为传入的值。如下:
select id,name,age from student where id =${id}
select id,name,age from student where id =1
5.MyBatis缓存
MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存,默认情况下,只有一级缓存默认开启。二级缓存需要手动开启和配置,他是基于namespace级别的缓存。一级缓存被称为sqlSession级别的缓存, 二级缓存被称为表级缓存。
一级缓存:
MyBatis的一级缓存默认是开启的,它在一个sqlSession会话里面的所有查询操作都会保存到缓存中,一般来说一个请求中的所有增删改查操作都是在同一个sqlSession里面的,所以我们可以认为每个请求都有自己的一级缓存,如果同一个sqlSession会话中2个查询中间有一个 insert 、update或delete 语句,那么之前查询的所有缓存都会清空。
使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话,在对数据库的一次会话中, 有可能会反复地执行完全相同的查询语句,每一次查询都会去查一次数据库,为了减少资源浪费,mybaits提供了一种缓存的方式(一级缓存)。
二级缓存:
二级缓存是全局的,也就是说;多个请求可以共用一个缓存,二级缓存需要手动开启。二级缓存针对的是同一个namespace,所以建议是在单表操作的Mapper中使用,或者是在相关表的Mapper文件中共享同一个缓存。一级缓存无过期时间,只有生命周期,缓存会先放在一级缓存中,当sqlSession会话提交或者关闭时才会将一级缓存刷新到二级缓存中;开启二级缓存后,用户查询时,会先去二级缓存中找,找不到在去一级缓存中找,然后才去数据库查询;
6.分页查询插件
使用分页助手插件有三个步骤:
1> 导入pagehelper坐标
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
2> 在核心配置文件中配置pageHelper
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--设置方言-->
<property name="helperDialect" value="mysql"/>
</plugin>
</plugins>
3> 测试
//设置分页相关参数
//pageNum 第几页 pageSize 一页多少条数据
PageHelper.startPage(2,3);
List<User> all = mapper.findAll();
for (User u : all) {
System.out.println(u);
}
4> 一些相关的API
// 获取与分页相关参数
PageInfo<User> pageInfo = new PageInfo<User>(all);
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示的条数:"+pageInfo.getPageSize());
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("上一页:"+pageInfo.getPrePage());
System.out.println("下一页:"+pageInfo.getNextPage());
System.out.println("是否是第一个:"+pageInfo.isIsFirstPage());
System.out.println("是否是最后一个:"+pageInfo.isIsLastPage());
System.out.println("所有参数信息:"+pageInfo.toString());
7.延时加载
MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询。延迟加载可以有效的减少数据库压力。
延迟加载类型及设定:通过对全局参数:lazyLoadingEnabled进行设置,默认就是false。 进行设置修改延时加载状态。
直接加载: 执行完对主加载对象的select语句,马上执行对关联对象的select查询。
<settings>
<!-- 延迟加载总开关 -->
<setting name="lazyLoadingEnabled" value="false"/>
</settings>
侵入式延迟:执行对主加载对象的查询时,不会执行对关联对象的查询。但要访问主加载对象的
某个属性(该属性不是关联对象的属性)时,就会马上执行关联对象的select查询。
<settings>
<!-- 延迟加载总开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 侵入式延迟加载开关 -->
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
深度延迟:执行对主加载对象的查询时,不会执行对关联对象的查询。访问主加载对象的详情时也不会执行关联对象的select查询。只有当真正访问关联对象的详情时,才会执行对关联对象的select查询。
<settings>
<!-- 延迟加载总开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 侵入式延迟加载开关 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>