0、插入一点mysql的东西
/** 存储过程2
* 存储过程有三种变量, IN:接收输入, OUT:输出,
*
* DELIMITER $$ 等价于 \d $ ,一回事儿哈,只是写起来简单些
*/
DELIMITER $$
CREATE PROCEDURE autoinsert_t112(IN a int)
begin
declare i int default 8;
while(i<=a) do
insert into t_student (name,age) values ('小明测试',i+100);
set i = i+1;
end while;
end $$
DELIMITER ;
SHOW PROCEDURE STATUS LIKE 'a%'
call autoinsert_t112(11);
上面新建的存储过程的 入参 IN 还可以传一个自己定义的变量:如下图
再看一下 输出:OUT
里面的INTO 表示把结果放到输出的变量里去。
然后怎么用呢? 如下图
把输出的结果 赋给 a 变量撒。。
那上图中的 @a 不好看啊,咋整??
再来个IN OUT的例子
工作中遇到的一些SQL
清数据 不删表:
删除表信息的方式有两种 :
truncate table table_name;
delete * from table_name;
注 : truncate操作中的table可以省略,delete操作中的*可以省略
truncate、delete 清空表数据的区别 :
1> truncate 是整体删除 (速度较快),delete是逐条删除 (速度较慢)
2> truncate 不写服务器 log,delete 写服务器 log,也就是 truncate 效率比 delete高的原因
3> truncate 不激活trigger (触发器),但是会重置Identity (标识列、自增字段),相当于自增列会被置为初始值,又重新从1开始记录,而不是接着原来的 ID数。而 delete 删除以后,identity 依旧是接着被删除的最近的那一条记录ID加1后进行记录。如果只需删除表中的部分记录,只能使用 DELETE语句配合 where条件
一、SSM整合并解决高并发
构建web服务SSM用的非常多,为什么用的多?
mybatis 可以基于注解和XML的提供SQL语句,基于原生的API和接口去访问数据库。
spring IOC整合service和其他依赖,IOC注入提供了很多种方式:基于XML的 基于注解的,基于javaconfig。
springMVC:restful接口设计和使用。 restful接口:很多互联网公司用的接口设计规范。
高并发的点和优化思路。
1、创项目,整合dao
要从官网获取相关配置 。。
mysql InnoDB才支持事务
show create table seckill\G 查看表是如何创建的,如果写了中文注释这里就一目了然。
JDBC也好,hibernate也好,mybatis也好,都是做映射这一层的(数据库的数据映射到对象,反过来把对象的数据映射到数据库),都是ORM框架
JDBC:完全手工的方式去拼写SQL,再拿到resultSet。
参数:例如entity
SQL:mybatis和hibernate最大区别就是SQL你自己去写,灵活性强,可以充分发挥SQL技巧。
然后拿到上面两个之后,把最终的结果Entity或者List,底层通过JDBC做封装,最后把结果返回给你。
也就是说mybatis就需要你的参数和SQL,其余的事帮你做了处理。
问题:
推荐Mapper自动实现
mybatis整合spring
更少的编码:
更少的配置:
稍微总结下:spring和mybatis的整合需要扫描的东西:
1、entity包的扫描
2、sql配置文件的扫描
3、Dap接口包的扫描
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据库连接池-->
<property name="dataSource" ref="dataSource"/>
<!--配置mybatis全局配置文件 classpath就是java下的目录,或者java的同级目录 resource-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--配置entity包,也就是实体类包,(自动扫描,用于别名配置) 包名+类名 统一转换成 等于类名 -->
<property name="typeAliasesPackage" value="org.seckill.entity"/>
<!--配置需要扫描的mapper.xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory,请注意不要使用sqlSessionFactoryBean,否则会出现注入异常,防止提前初始化sqlSessionFactory-->
<!--因为在初始化MapperScannerConfigurer的时候,可能jdbc.properties文件还没有被加载,那这样的话拿到的datasource就是错的-->
<!--而sqlSessionFactoryBeanName的意思是,当我们去用mybatis的时候,它才会去找sqlSessionFactory,所以不用出错-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--给出要扫描的mapper接口、-->
<property name="basePackage" value="org.seckill.dao"/>
</bean>
小总结一下SSM整合的时候,扫描的东西,除了上面spring-dao的几个扫描
spring整合service的扫描:
<!--配置自动扫描service包下的注解,在这里配置了自动扫描后,com.suny.service包下所有带有@Service注解的类都会被加入Spring容器中-->
<context:component-scan base-package="org.seckill.service"/>
spring和springMVC整合的扫描:(其实这二者不需要整合)
<context:component-scan base-package="org.seckill.web" />
###2、整合service
1、DTO包:数据传输层,关注是web和service之间的数据传递。。。。
最终早controller里面返回给页面的result的泛型<>里面,都是DTO包里面的类。。。
public SeckillResult<Exposer> exposer(@PathVariable("seckillId") Long seckillId) {
public SeckillResult<SeckillExecution> execute(@PathVariable("seckillId") long seckillId,
entity包:数据库表对应的封装
2、这里面的抛异常有个要注意的:
1)、统一异常处理的思路
2)、其他的异常也要转化成我们的自定义异常,或者是runtimeException。
回想公司的项目也是一样的道理,所有的exception都转化成了I18nException。。
这里要特别注意,看慕课网的代码是如何写的。。。。
catch (SeckillCloseException e1){ //子类的异常要捕获,不然就变成父类异常看不到了
throw e1;
}catch (RepeatKillException e2){
throw e2;
}catch (Exception e){
log.error("error:{}",e);
//所有编译期异常 转化成 运行期异常
throw new SeckillException(e.getMessage());
}
3、service对下面层次的依赖
service 依赖于 很多dao ,dao依赖于sqlsessionfactory,sqlsessionfactory依赖于datasource
为什么IOC(或者IOC的好处):
1、对象创建由容器统一托管,而不是通过new的方式。
2、规范的生命周期管理:(不重要,看看就好)
有一些规范的生命周期(inti啊,destory啊等),可以在任意的生命周期点上加入我们的业务逻辑。
3、灵活的依赖注入:
可以通过编程,也可以通过注解,也可以通过第三方框架自动帮我们整合,像mybatis-spring的整合包,帮我们自动完成dao的创建、注入。
4、IOC的注入方式
XML中:
一些命名空间的控制:
比如context帮我们方便的实现包扫描
mvc:就是帮我们做springMVC的一些配置
注解:
用于自己开发的类,比如service,controller等,告诉spring要交给容器去托管。。
为什么spring的@Autowired注入,不需要写set get方法:
看spring源码就会知道,没有get/set方法时,spring会通过反射对属性赋值。
当然你写get/set方法也可以。。
5、声明式事务
一句话:声明式事务目的就是帮我们去解脱事务程序,也就是说我们实际的开发当中,是不应该关心事务什么时候提交,什么时候回滚。而是交给第三方框架,比如spring,它来帮我们管理。。。
这样一个全自动的方式,叫做声明式事务。。。
6、spring声明事务的使用方式,
推荐第三种,第一个可以不看。
7、事务方法嵌套
事务方法嵌套是声明式事务独有的概念,这是它自己的概念,(和mysql是没有关系的)
什么意思? 这就体现在它的传播行为上,当有多个方法调用的是它是创建一个新事务,还是加入到已有的事务的时候,这是它的一个传播行为。。spring默认的传播行为是。。。(如图)
这个行为的意思是:它有一个新的事务加入进来的时候,如果有就加入到原有的事务,如果没有就创一个新的。这个行为适合于大多数,当然还有很多行为,(可自行研究)。。
8、事务回滚
默认是抛出runtimeException才会 回滚。。
9、配置事务管理器
首先是配置在spring-service.xml里,。。
1、用哪个 事务管理器 呢?
mybatis采用的是JDBC的事务管理器
(注意:IDEA里面,事务管理器下面的数据源的ref标红,这个不要紧,因为在spring-dao.xml里面也配置了,只是在不同的文件里面,IDEA是标红的。只要项目整体运行起来之后,就能找到那个datasource)
然后就是配置 基于注解的声明式事务,意思就是 用注解来标识 某一个方法是事务方法。。
10、使用注解控制事务方法的优点:
注意1:尽量不使用,一次配置永久生效的方式,因为事务是一个很小心的行为,一旦用不好很容易出错。。
基于注解使用事务的好处:
注意2:当我们需要两条或者以上的修改操作 需要同时去完成,才需要spring去给你封装一层事务控制。否则不需要。
1、基于tx/aop的实现
在哪个切入点上(aop:pointcut),引用哪个增强(txAdvice)
切入点:应用在哪个方法上,。
增强:就是txAdvice
(类上不用改了,这种方式是自动生成代理,spring在service类实例化的时候就生成了代理对象并且注入,而且已经增强了。。。)
关于事务增强的几个属性:
只读的话,就是不能进行增删改的操作了。。。
2、基于注解的实现(写起来最简单)
隔离级别啊(spring用数据库默认的隔离级别),传播行为啊,只读啊,都可以在@Transactional里面配置
xml中这么配:
类中或者类中的方法上,这么用:
关于spring事务可以看看这篇文章:
https://blog.csdn.net/bao19901210/article/details/41724355
spring事务和数据库事务的关系:
https://zhidao.baidu.com/question/1607154147351195507.html
注意看spring的 一个默认事务传播级别:PROPAGATION_REQUIRED…
它可以保证我们业务层方法间相互调用的时候,这两个方法在一个事务当中。。。
(也就是说service里面的几个dao共用一个事务,只要一个SQL执行失败,都会导致其它的方法回滚 (rollback)) 看看下面这个博客:
https://blog.csdn.net/bigtree_3721/article/details/53966617
###3、整合web
本节内容主要讲解
1、前端交互设计
2、Restful : 它是用来规范我们的url的设计规范,
3、springMVC使用
4、bootstrap+jQuery
####1、根据需求设计前端交互流程
在这一部分公司一般涉及三个职位:
1、 产品、前端、后端
产品:解读用户需求,设计一个满足用户需求的一个文档。
拿到这个文档之后,前端主要负责页面、做一些页面展示和动作细节
后端的主要负责存储,给前端数据。还有一些其他业务:比如下发控制器。
前端页面流程:
详情页流程:
1、获得标准系统时间,就是服务器的时间。因为不同的客户的时间都不一样。
####2、Restful
用来规范我们的url的设计规范,表示的是一种资源的状态和 状态转移。。
比如查询一些详情信息的时候,用get,表示的是查看资源的一种状态。。
删除、修改的时候表示状态的转移,用put或者post。。
GET /seckill/list
POST /seckill/{seckillId}/execution
注意这里用第二种,解读:
1、/seckill 表示一个资源的模块。。
2、/seckill/{seckillId} 表示具体哪一个资源
(execution 注意是名词,执行器,表示一种状态,意思是我要去执行秒杀这个操作),动作是通过POST去体现的。
3、同理、这里的delete也要理解成一个名词
4、常见的:
POST、PUT区别其实就是:
POST是非 幂等的操作
PUT 是幂等操作。。
一般来讲,没有太严格的区分。
5、几个优雅的URL展示:
再看看秒杀业务的API
###4、springMVC框架
1、大致复习下springMVC基本东西
使用springMVC使用是围绕着handler来开发,handler的产出其实就是两部分:数据model和页面view。
model就是我们的数据要放到model当中,你可以简单理解为是一个Map。
view 就是我们展示页面的格式,可以是JSON,JSP,PDF等。
springMVC运行流程:自己去查看 doc笔记。。。。(很详细了),还有
关键词记忆:
首先浏览器发送一个HTTP请求,它会到servlet容器中,比如tomcat。
前端控制器 调 mapping去找、 调adapter去执行、调viewResovler去解析
2、映射
springMVC支持很多形式的 映射,也支持RESTFul风格的URL。。
注意cookie的映射
3、整合springMVC
略过,看码云上的项目
4、高并发
4.1:可能出现高并发的点:图中红色的部分。。
##二、mybatis源码
MapperRegistry.java 的
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();//从这来的
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type); //代理工厂从这来的
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession); //拿代理
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
1、从代理工厂mapperProxyFactory中拿一个代理,代理工厂mapperProxyFactory怎么来的?
从这来的:
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
从knownMappers 来的,它是一个map
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
2、那knownMappers 又是从哪来的?
从 public <T> void addMapper(Class<T> type) {}方法中的
this.knownMappers.put(type, new MapperProxyFactory(type));中来的。。
3、那addMapper方法又是被谁调用的呢? 因为调用了这个方法才能给knownMappers 初始化啊。。
答:是去加载配置文件的时候调用的。也就是
new SqlSessionFactoryBuilder().build(reader); build的时候调用的。。
加载配置文件的时候不断的去调用addMapper方法,为不同的class对象去创建代理工厂。。
也就是说mybatis通过加载配置文件已经为接口class 创建好了一个代理工厂。。(重要结论。。。)
加载配置文件怎么就能创建代理呢?
答:配置文件的namespace就是接口名称,所以加载配置文件时一定有这样一行代码Class.forName(...),来加载一个接口。
然后去调用addMapper方法,将上面加载好的class传进来。这样就提前给接口class创建好了代理工厂
4、那代理工厂是怎么生产(也就是创建)代理的呢?这里就是获得最后的代理实例。
MapperProxyFactory.java的
public T newInstance(SqlSession sqlSession) { //通过它创的
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); //相当于是invoktionHandler的实现类,假设有了它
return this.newInstance(mapperProxy); //它去调用另一个方法,见下面
}
protected T newInstance(MapperProxy<T> mapperProxy) { //就是它
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); //这个就是JDK的动态代理实现。返回一个代理。(其实这里有一个强转。)
}
5、那mapperProxy是怎么来的? 因为调用接口方法的时候 实际上 是去调用mapperProxy的invoke方法的。
看看这个类:MapperProxy
public class MapperProxy<T> implements InvocationHandler, Serializable {} 它实现了InvocationHandler接口,和预期一致。。
6、下面仔细看看mapperProxy的invoke方法。。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这个if也不能被执行,为啥?接口是没有实现类的,怎么能用反射去调用一个没有实现类的方法呢? 不行的
if (Object.class.equals(method.getDeclaringClass())) {//这个if是不会执行的,也不能执行
try {
//这个和原本动态动态代理有点区别:这个接口是没有实现类的。所以是不能调用method.invoke的
return method.invoke(this, args);
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
} else {
//所以调用接口方法 就是下面这些代码来实现的。。。。
//最重要的:调用接口方法其实就是去执行SQL语句啊,也就是execute方法,所以execute方法是最核心的方法
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}
private MapperMethod cachedMapperMethod(Method method) {
//这个methodCache是那个代理工厂传进来的,
MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
if (mapperMethod == null) {//第一次会执行这个if
//这里就是为什么接口方法可以和sql对应上的。因为有一个getConfiguration()得到配置信息
mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
this.methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
7、最终的执行SQL的地方(部分代码) 这里还是用sqlSession去执行SQL
public Object execute(SqlSession sqlSession, Object[] args) {
Object param;
Object result;
if (SqlCommandType.INSERT == this.command.getType()) {
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
}
大致流程如下:(模拟一个假流程,方便理解)
1、
2、这里的代理工厂没有模拟,就写了一个代理类(其实就是invoktionHandler)
3、这个代理类的invoke是关键的关键。。。
invoke方法是最终调用SQL语句的地方。。。