1.1.mybaties

(一)mybatis入门

1.mybatis简介

mybatis是一个持久层框架(ORM对象关系映射框架),是对jdbc技术的封装,简化的开发代码,提高开发效率

持久层技术:jdbc,DBUtils,mybatis,hibernate,jpa,mybatisplus

orm:对象与对象之间的关系映射,持有关系,聚合关系,《uml模型设计》

2.快速入门mybatis使用

1.安装mybatis
	两个jar包:一个mybatis的核心包,一个mysql数据库驱动包

2.创建mybais的核心xml配置文件
	在src下创建mybatis-config.xml配置文件
3.创建实体类与xml映射文件
	切记把创建的xml映射文件加入到配置文件中
4.调用mybatis的api来加载xml配置文件

5.执行数据操作

3.认识mybatis的核心对象

1.SqlSessionFactoryBuilder:该对象作用是build方法用来加载并解析xml配置文件,解析配置文件中的各种标签(如:properties,settings,typeAliases,environments,mappers),解析完成该对象可销毁。
2.SqlSessionFactory:sql会话工厂对象。该对象只有opemSession方法,理解成DataSource连接池。生命周期:全局唯一对象。
3.SqlSession:sql会话对象,理解成一个Connection链接,做数据库操作,执行完成后关系会话对象。生命周期:随用随开,用完即关。该对象中的几个重要方法:seleceOne,selectList,insert,delete,update,getMapper

4.认识mybatis的核心配置文件,mybatis-config.xml

<!--多数据库环境-->
    <environments default="goods">
        <!--id是自定义的数据库环境名称-->
        <environment id="goods">
            <!--事务管理器-type:
            JDBC:开启事务
            MANAGED:不开事务-->
            <transactionManager type="JDBC"></transactionManager>
            <!--type:UNPOOLED|POOLED|JNDI-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/704b"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--把映射文件集成到配置文件中,为了在调用build方法时,能够解析映射文件-->
    <mappers>
        <mapper resource="com\javasm\sys\mapper\sysuserMapper.xml"></mapper>
    </mappers>

配置文件常用标签

加载properties文件:<properties resource="">

配置:
<settings>
	<setting name="logImpl" value="STDOUT_LOGGING">
	<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
别名:要求绝对不能出现同名的类,mybatis内建别名
<typeAlias>
	<package name="">
</typeAlias>

5.认识mybatis的映射文件

1.根标签mapper的namespace属性:
	不同的映射文件通过namespace来区别,不能同名.
2.查询语句select标签,id,parameterType,resultType属性:
	id:在同一个映射文件中,id必须唯一;
	parameterType:可省略,一般都写上,表示在调用selectOne或selectList或insert,delete,update方法时传入的参数类型.
	resultType:数据库查询结果的单行记录封装的类型.(一般是实体类或Map,简单类型)
3.sql语句中的#{}与${}表达式获取参数
	两者作用是一致的,都是用来获取参数的,
	#{} 底层采用sql语句预编译,PrepareStatement
	${} 底层采用Statement对象来执行sql操作,适合于用在动态排序.

6.认识SqlSession对象中常用方法

selectOne("",Object)
selectList("namespace.id",Object)
insert
delete
update
getMapper(Class clz)重要

7.多参数传递

1.把多个参数封装实体类
2.把多个参数封装到map
3.在映射接口的方法的每个形参上加@Param注解指定名称.#{param注解的名称}

8.模糊查询

<select id="selectRolesByRoleName" parameterType="String" resultType="Sysrole">
  select * from sysrole where rname like "%"#{rname}"%"  order by update_time desc
</select>

9.使用mybatis过程中常见的异常信息

1.实体类没有对应的get方法,错误原因:#{写错}
org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'rid22' in 'class com.javasm.sys.entity.Sysrole'

2.映射文件中id重名
Error parsing Mapper XML. The XML location is 'com\javasm\sys\mapper\sysroleMapper2.xml'. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.javasm.sys.mapper.SysroleMapper.selectRolesOrder

3.调用的方法,在映射文件中是不存在的(接口中有方法,映射文件中没有)
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.javasm.sys.mapper.SysroleMapper.selectRolesByRoleName2

其他注意点:

date:年月日

datetime:年月日时分秒

timestamp:时间戳字段,能够根据时间戳自动更新值。带毫秒类型字段,一般用在createTime与updateTime字段上,能够根据时间戳自动更新。制定默认值now(),CURRENT_TIMESTAMP

切记select列表查询指定order by update_time desc

后续项目中主键不再使用自增id,为了后续的数据库分库分表,id设计为varchar型,添加数据的时候手工指定id,UUID

数据库字段名不允许a_colmn的名称,实体类的属性名不允许aColumn,不允许is开头。

总结:善于总结

1.配置文件(官网可以查询相关设置的信息)
	settings标签中的配置,配置日志,配置驼峰命名映射
	typeAlias配置别名
	
2.代码:
	SqlSessionFactoryBuilder:
		作用:加载配置文件初始化连接池,解析映射文件到内存
		生命周期:new SqlSessionFactoryBuilder().build()完成该对象可销毁
		
	SqlSessionFactroy:
		作用:持有了第一步创建出来的连接池与映射文件信息
		生命周期:全局唯一.单例
	
	SqlSession:
		作用:执行数据库操作,主要方法:selectOne.selectList,getMapper
		生命周期:随用随开,用完关闭
		
3.映射文件(最重要)
	根标签mapper的namespace属性值,必须是接口的全名称(包名.类名)
	select子标签,属性:id,resultType,parameterType
	获取动态参数表达式:#{}

(二)mybatis使用

1.curd

insert,delete,update标签来说,没有resultType属性,默认返回int;

分清楚这四个标签,对应四种sql语句

对于insert语句,如果主键策略是自增:
 <insert id="addUser" parameterType="Sysuser" useGeneratedKeys="true" keyProperty="uid">
insert into sysuser(uname, upwd, uphone, rid) values (#{uname},#{upwd},#{uphone},#{rid})
</insert>
    
对于insert语句,如果主键策略是自定义:需要在insert语句传参的时候,自己设置id值.
 Syspermission p = new Syspermission();
 p.setPerid(UUIDUtil.getuid());

2.sql标签

公共sql语句部分独立提取,在具体的sql语句中通过include标签引入sql语句

<sql id="userFields">
        uid,uname,upwd,uphone,create_time,update_time,rid
</sql>

select <include refid="userFields"></include> from sysuser where uid=#{uid}

3.resultmap

对数据库表字段与实体类的成员变量做映射,

如果字段名与成员变量名一致,不需要做映射.

如果字段名采用_分割,成员变量名驼峰命名,也不需要映射.

resultType:是select标签的结果集映射属性,值一般写的简单类型(String,Integer...),实体类,Map

resultMap:是select标签的结果集映射属性,值写resultMap标签的id值.
<resultMap id="自定义id名" type="类名">
        <id column="主键列名" property="类中的主键属性名"></id><!--对主键列映射-->
        <result column="非主键列名" property="属性名" ></result><!--非主键列映射-->
</resultMap>

<!--resultType与resultMap不能同时出现-->
<select id="selectByKey" parameterType="String" resultMap="自定义id名">
</select>

4.对象关系映射

持有关系:用户对象持有角色对象。

场景:查询用户对象时,级联查询用户持有角色

1.(建议)进行多次单表查询:手工发起多次查询请求,先查询用户,根据查询的用户对象得到角色id,再发起第二次查询,根据角色id查询角色对象,然后组合。

2.仍然是保持单表查询:使用mybatis内的resultMap标签的子标签association
<association property="关联对象的属性名" javaType="关联对象的类型,类名" column="要传入二次查询的数值列名" select="二次查询的位置">

3.(偶尔使用)进行sql语句的多表关联查询:使用mybatis内的resultMap标签的子标签association
<association property="关联对象的属性名" javaType="关联对象的类型,类名">
	<id>
	<result>
</association>

聚合关系:角色对象聚合了用户对象。

场景:查询角色对象时,级联查询角色下的所有用户对象。

1.(建议)进行多次单表查询:手工发起多次查询请求,先查询角色,再根据角色id查询用户表,得到用户列表,然后组合。

2.仍然是保持单表查询:使用mybatis内的resultMap标签的子标签collection
<collection property="关联对象的属性名" ofType="集合的泛型类型,类名" column="要传入二次查询的数值列名" select="二次查询的位置">

3.(偶尔使用)进行sql语句的多表关联查询:使用mybatis内的resultMap标签的子标签collection
<collection property="关联对象的属性名" ofType="关联对象的类型,类名">
	<id>
	<result>
</collection>

(注意数据库表之间的是多对多的设计时候如何实现)

5.动态sql语句,重要

在xml映射文件中进行sql语句拼接.

注意点:实体类中的成员变量不能使用基本类型。

1.where标签:生成where关键字,并去掉紧跟其后的and或or;
	where标签的trim写法:<trim prefix="WHERE" prefixOverrides="AND |OR ">
2.if标签:test属性值为boolea表达式;
3.set标签:用在update语句中,生成set关键字,并去掉最后的逗号;
	set标签的trim写法:<trim prefix="SET" suffixOverrides=",">
4.choose (when, otherwise),与java代码的switch-case-default语法一样.不重要
5.foreach标签:用在批量删除,批量添加
collection:如果传入的参数是数组,写array;如果是List,写list;如果@Param自定义,写自定义
<foreach collection="array|list|自定义" open="(" close=")" item="循环变量" separator="分割符">
    #{循环变量}
</foreach>

注意点:

1.实体类成员变量类型不要使用基本类型,使用包装类对象

2.慎用long型变量,因为前端js语言

3.项目中不允许在视图上显示数据id信息.

总结:

1.写select,insert,delete,update,还要会数据库自增id策略,能够获取新增记录id;
2.动态sql语句,if,where,set,foreach批量删除。
3.相关任务:把用户,角色,权限,角色权限关系表创建好,对应mapper接口,mapper映射文件写好,
	接口中的方法:用户接口(curd,用户设置角色方法)
		        角色接口(curd,获取角色下权限列表;删除角色下的权限,为角色设置权限列表)
		        权限接口(curd,新增的时候排序字段赋值;调整菜单显示顺序)
		        

(三)mybatis的理解

1.源码分析

1.1. SqlSessionFactoryBuilder方法

帮助理解mybatis原理。通过debug调试阅读源码。

Configuration对象内部:

一个个configuration的子标签单独进行解析
 Configuration{
     Properties variables;//保存的是properties标签的配置的数据
     TypeAliasRegistry typeAliasRegistry;//保存对象别名数据
     Environment environment;//保存的数据源对象
     Map<String, MappedStatement> mappedStatements;//保存的是解析的映射文件中的curd标签(key:namespace.id,value:statement对象)
 }

build方法内部

//解析配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(InputStream in)
parser.parse()

XMLConfigBuilder的parse方法内部:

 this.propertiesElement(root.evalNode("properties")){
     this.configuration.setVariables(defaults);
 }
 this.typeAliasesElement(root.evalNode("typeAliases"));
 this.mapperElement(root.evalNode("mappers"));

this.mapperElement方法内部:

//解析映射文件
XMLMapperBuilder builder = new XMLMapperBuilder(InputStream mapperXML,this.configuration)
builder.parse()

XMLMapperBuilder的parse内部:

configurationElement(){
    buildStatementFromContext(insert|select|delete|update标签)
    XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration,传入的单独某个curd标签)
    
    MappedStatement statement;//每个curd标签都会被封装成该对象(id,sqlSource,sqlCommentType,parameterType,resultType,resultMap)
}

最终

return new DefaultSqlSessionFactory(configuration)

1.2.创建session

 SqlSession session = new DefaultSqlSession(this.configuration, executor, autoCommit);

1.3.SqlSession的getMapper方法

//传入接口类对象,得到一个代理对象工厂
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(SysuserMapper.class);

SysuserMapper userMapper = mapperProxyFactory.newInstance(sqlSession);

//
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);

//代理模式
Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);

//当我们调用SysuserMapper对象中的方法时,进入了MapperProxy对象invoke方法中
invoke方法内:把我们正在调用的方法封装了MapperMethod对象
mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());

单一性原则(对象职责单一,方法职责单一),保证复用,代码精简,代码重构

构建者模式:造对象,构建一个复杂单例对象

工厂模式:造对象,构造N个对象

2.代理模式

有助于我们理解spring的aop

有什么用?

当一个已经存在的对象中的某个方法不满足需求时,无法改源码,引入代理模式。

怎么实现?

1.使用静态代理
记着两个要点:第一:被代理对象与代理对象同接口;第二:代理对象持有被代理对象

2.动态代理,使用Proxy类或者使用第三方组件cglib.jar
在运行期间由jvm动态的在内存中创建出代理类($proxy0),并实例化,然后返回实例化出来的代理对象,动态创建的代理类中持有了InvocationHandler对象的引用;代理类与被代理类同接口

动态生成代理类的结构:

Proxy{
    protected InvocationHandler h;
    Proxy(InvocationHandler h){
        this.h=h;
    }
}


//因为$Proxy0已经使用extends关键继承自Proxy类,而我们要达到代理对象与被代理对象同类型,只能使用implements关键字从接口派生,如果被代理对象没有接口的话,Proxy创建代理对象就不能使用。
public final class $Proxy0 extends Proxy implements IConnection{
     protected InvocationHandler h;
     
     public String begin(Integer num,String str){
         return this.h.invoe(this,Method,new Object[]{num,str})
     }
}

3.数据延迟加载

这里是针对于使用mybatis的对象关系映射的时候才有效。

 <!--开启关联对象的延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"></setting>
        <!--触发延迟加载属性加载的方法,默认equals,clone,hashcode,toString-->
        <setting name="lazyLoadTriggerMethods" value=""></setting>
        <!--积极加载-->
        <setting name="aggressiveLazyLoading" value="false"></setting>

开发项目要有延迟加载的思想:

分页,树形结构,数据用到才加载,网页图片的延迟加载

4.缓存设计,(不常用)

缓存:基于内存把数据暂存到内存中。

标准缓存套路:发起查询,先去内存中查找数据是否存在,存在则返回;不存在则查询数据库,把查询结果临时保存到内存中。

mybatis分为两级缓存。

一级:session级别缓存:在同一个会话中发起相同的查询,除了第一次查询数据库,后面的查询都是从SqlSession的缓存数据中获取。会话级别的缓存默认是开启的。

二级:sessionFactory级别缓存:多个会话之间能够共享缓存。适合于web系统开发。

开启二级缓存:

 <!--配置文件开启二级缓存-->
<setting name="cacheEnabled" value="true"></setting>
<!--映射文件配置二级缓存策略-->
    <cache eviction="FIFO"
            flushInterval="600000"
            size="512"
            readOnly="true"/>
            
  <select useCache="false">表示这个查询禁用缓存
  <update flushCache="true">
  <delete flushCache="true">修改和删除数据时,可以指定flushCache实时清空缓存。

总结mybatis执行流程:

1.初始化过程:通过SqlSessionFactoryBuilder对象的build方法内部来解析mybatis配置文件,针对该配置文件中的各个子标签分别进行解析,比如properties,settings,typeAlias,mappers等。把解析出来的配置数据保存在全局唯一的Configuration对象中。针对于mappers子标签中的映射文件,通过XmlMapperBuilder构建者中的方法对映射文件进行独立解析,把映射文件中的select,insert,update,delete标签解析为Mybatis的MappedStatement对象,并把该对象加入全局Configuration对象中,并把Configurationb对象封装到DefaultSqlSessionFactory对象中。

2.数据库操作过程:进行数据库的curd操作时,从全局Factory中得到一个临时的SqlSession会话对象,该对象仍然持有Configuration对象,通过会话对象的getMapper方法得到一个mapper接口的代理对象,内部是通过jdk的Proxy类来创建的接口代理对象,拿到该代理对象的引用后,执行代理对象中的方法,进入MapperProxy对象的invoke方法,invode方法内通过反射得到调用方法所在类名与方法名,组装成一个字符串,该字符串与第一步初始化时解析的MappedStatement的id对应,可以得到一个MappedStatement对象,判断该操作时select,insert,delte,update,执行sqlSession的selectOne,selectList,insert,delete,update等方法,如果是查询的话,把查询结果进行封装(判断返回值类型是集合,实体,map)。最后关闭会话。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值