最近忙里偷闲又看了一遍《Mybatis深入浅出》
这里大多数是mybatis内容,当然也涉及到别的
作为两大流行框架,所以Mybatis里边多少也要介绍下springMvc
三层架构和SpringMVC概述_swadian2008的博客-CSDN博客_springmvc三层架构目录一、关于三层架构和MVC1、三层架构(1)表现层(2)业务层(3)持久层2、MVC 模型3、经典三层架构和MVC的关系二、SpringMVC 概述1、SpringMVC的优势2、SpringMVC 和 Struts2 的优略分析一、关于三层架构和MVC1、三层架构 我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S架构的开发。.https://blog.csdn.net/swadian2008/article/details/113474146
先说结论,mvc和经典三层架构其实没什么太大关系
表现层,业务层,持久层
MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller) 的缩写, 是一种用于设计创建 Web 应用程序表现层的模式。
MVC 中每个部分各司其职:
Model(模型): 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
View(视图): 通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。 通常视图是依据模型数据创建的。
Controller(控制器): 是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。
顶多是都有分层解耦的思想,或者说mvc只能算三层架构中的展现层
看mybatis日志正好看到了log4j,又一想我们写代码的时候都有@Slf4j,他们到底什么关系?
接口和实现
log4j与slf4j的区别_你可拉倒吧的博客-CSDN博客_slf4j和log4j
为什么叫4j,原来是for java的意思
log4j : 即 log for java;Java的日志4英文名 four 与for同音
slf4j : simple log facade for java :简单日志门面
区别:
log4j是真正实现日志功能的产品,像这样的产品有很多
slf4j 是一个适配器,我们通过调用slf4j的日志方法统一打印我们的日志,而可以忽略其他日志的具体方法,这样,当我们的系统换了一个日志源后,不需要更改代码:
所以不管我们实现用的是Logback还是log4j,在代码中直接用@Slf4j注解就好了,就算更改了日志实现,那代码里打印日志的部分也不用动
blob和text区别_王奕然的博客-CSDN博客_blob text区别
1.blob用来存文件的二进制字节,而text用来存文本
2.但是一般情况下我们是要有一个文件服务器的,不建议把文件的字节存到数据库,如果文件过大容易引起内存溢出
3.text可以看作varchar长度不足时的扩展
以前看面试题的时候,一直不知道我们spring的@Transactional注解和数据库事务的几个隔离级别到底什么关系,其实我们操作事务不就是数据库事务嘛!
1.@Transactional需要看底层数据库是否支持事务,比如mysql的myisam是不支持事务的,所以这时候加了@Transactional也不生效
2.@Transactional的隔离级别也要看底层数据库所支持的隔离级别,比如@Transactional有默认隔离级别,这默认的就是底层数据库的默认隔离级别,比如oracle默认为读已提交,mysql默认为可重复读。而且隔离级别也要看底层数据库支持什么,比如oracle不支持脏读这个隔离级别。
3.@Transactional的几个禁忌,不能try catch,不能非public,不能自调用
读未提交,读已提交,可重复读,序列化
这是数据库的隔离级别,当时你在@Transactional注解的Isolation属性里边也都能找到对应的
四个隔离级别分别会产生怎样的问题
读未提交---脏读,事务A读到了事务B未提交的数据,拿着这个数据进行逻辑处理,后来事务B发生了异常回滚了,那事务A就是拿着错误数据进行逻辑处理了
读已提交---不可重复读,一对夫妻公用一个账号消费,先生看到卡里剩八百,就想买个500的西装,但是他付款之前,女士消费了500烫头,那先生付款时候就报余额不足,尴尬了
为了避免这种尴尬,可以把隔离级别提升未可重复读。可重复读我理解是把某一条数据在读取时候给锁上了,直到用完才解锁。
可重复读---幻读,可重复读是针对一条记录,但是多条记录时就可能产生问题。女士要打印这个月的消费记录,她肯定先查询再打印,她查询时候发现这个月有十条消费记录总计1000,然后此时先生去消费了800,那女士点击打印打印出来的就是11条记录总计1800,这个时候女士以为自己看错了产生了幻觉所以叫幻读。
解决幻读的办法就是再提升一个隔离级别---序列化,序列化就是把操作排好序,像队列一样一个操作执行完才能按顺序执行下一个操作。
但是随着隔离级别的提升,效率也在降低,所以一般就用读已提交这种隔离级别
以前以为synchronized就完事大吉了,但是前几天才知道分布式情况下synchronized并不能保证安全性。因为synchronized只能锁自己jvm中的对象,本地锁,但是比如现在有两个服务,那我同时访问两个服务的同一个synchronized方法,此时就会产生并发问题。
然后照同事抄了一个zk分布式锁才解决问题。
数组里只包含一个元素那可以直接用Collections.singletonList(),但是如果你之后还有增加,那就不行了。Collections.singletonList()返回的是不可变的集合,但是这个长度的集合只有1,可以减少内存空间。但是返回的值依然是Collections的内部实现类,同样没有add的方法,调用add,set方法会报错。
2019-03-20 mybatis实体为什么要提供一个无参的构造函数 - 简书
Class.forName("className").newInstance();
我们在返回查询结果时候,mybatis会根据resultType或者resultMap中的type 获得类的全路径名
有一点要注意:@Builder也会覆盖无参构造方法
mybatis只有一个接口,但是它可以调用指定namespace中得sql,怎么做到的,就是动态代理。
1.xml中命名空间namespace要跟接口得全路径名对应,
2.xml中的sql的id要和方法名对应,namespace+id在整个项目中要唯一,否则mybatis会报错,就像你controller中的requestMapping中的url在整个项目中不唯一的话,spring会给你报错一样
3.在配置类上使用@Mapperscan配置接口包的路径,或者每个接口上都用@Mapper修饰。@MapperScan和@Mapper是Mybatis注解,用于把接口绑定动态代理,并交由Spring管理
MyBatis进阶之接口代理方式_heromps的博客-CSDN博客_mybatis接口代理
Mybatis源码-加载映射文件与动态代理 - SegmentFault 思否
调用其MapperMethod的execute()方法,而通过上面的分析已经知道,MapperMethod中的SqlCommand关联着MappedStatement,而MappedStatement中包含着和被调用方法所关联的SQL信息,结合着SqlSession,就可以完成对数据库的操作。关于如何对数据库操作,将在后续的文章中介绍,本篇文章对于Mybatis中的动态代理的分析就到此为止。最后以一张图归纳一下Mybatis中的动态代理执行流程,如下所示。
这个用的比较少,一般都是代码里设置好Id再存入数据库,就算是用sequence也是先读出来sequence再拼接到id里边去,这个功能还是实习时候用过
MyBatis中主键回填的两种实现方式-蒲公英云
insert into t_book (b_name,author) values (#{name},#{author});
其中keyProperty实体中的属性名,如果你实体中要用userId接回写的主键,那
insert into t_book (b_name,author) values (#{name},#{author});
关于Mybatis中keyProperty属性_m0_67401920的博客-CSDN博客_mybatis 的keyproperty
selectKey标签
SELECT LAST_INSERT_ID()
insert into t_book (b_name,author) values (#{ name},#{ author});
我一般什么情况下用到:mybatis-generate插件自动生成的xml我肯定不能手动去改的,但是我自定义的xml还想用自动生成xml中的信息,比如BaseResultMap
https://www.jb51.net/article/220690.htm#_label1https://www.jb51.net/article/220690.htm#_label1
public interface TagExtendMapper extends TagMapper {
...
}
...
或者
on条件与where条件的区别_游子心的博客-CSDN博客_on和where的区别
mybatis没有现成的TypeHandler,需要自定义一个TypeHandler,所以一般都会用array_to_string转成字符串返回。
array_to_string(array_agg(distinct orderItem.order_code),',')
排除空元素
array_remove(array_agg(distinct order_item.ORDER_STATUS),null) order_status_list
ARRAY_LENGTH(array_agg(distinct orderItem.order_code),1)
那个1是一维数组的意思
if ARRAY_LENGTH(temp.order_status_list,1)>1
if 'DONE'= ANY (array_agg(distinct orderItem.order_code))
array_agg(distinct orderItem.order_code) @> array_agg(distinct item.order_code)
ARRAY[1,4,3] && ARRAY[2,1] 返回true