Open GenweiWu opened 3 years ago
ORM(Object relational Mapping)是对象关系映射,用来将关系型数据库的数据和java Bean进行映射,将程序对象保存到数据库中去
Mybatis是优秀的持久层框架,是半自动的ORM框架
它支持定制sql语句、存储过程、高级的字段映射
需要频繁建立数据库连接,以及释放数据库连接;建议使用数据库连接池;
Mybatis可以配置数据库连接池,也不用显示的每次去获取数据库连接,释放连接
sql语句是通过字符串的方式写在java代码里的,查看维护都很麻烦;如果再遇到条件判断ifelse,就更加复杂
Mybatis是将sql语句写在xml文件中的,方便维护管理
向sql语句传参数很麻烦,展位附近要考虑下标是0,1这种
Mybatis是自动映射,可以通过将javaBean
和sql中的字段映射起来
sql返回结果需要遍历resultSet,无法自动映射为POJO(javaBean)
Mybatis可以自动将结果映射为java bean
相对于传统JDBC:
sql
),以及sql片段复用(include
)缺点:
相对于Hibernate:
Hibernate | Mybatis | |
---|---|---|
全自动的ORM框架 | 半自动的ORM框架 | |
支持数据库无关性,切换数据库自动兼容 | 切换数据库要修改sql | |
门槛高,适合需求变化少,逻辑简单的系统 | 门槛低,适合复杂逻辑系统 |
数据库驱动将sql语句+参数发送给DBMS(数据库管理系统,比如Mysql)前先进行编译,DBMS收到sql后就不用再次编译
支持,通过代理模式进行懒加载
https://juejin.cn/post/6844904062362583054 主要是利用association的column指定查询id,设置select内容来指定延迟查询的sql的id
<mapper namespace="cn.ideal.mapper.AccountMapper"> <!-- 定义封装 Account和User 的resultMap --> <resultMap id="userAccountMap" type="Account"> <id property="id" column="id"></id> <result property="uid" column="uid"></result> <result property="money" column="money"></result> <!-- 配置封装 User 的内容 select:查询用户的唯一标识 column:用户根据id查询的时候,需要的参数值 --> <association property="user" column="uid" javaType="User" select="cn.ideal.mapper.UserMapper.findById"></association> </resultMap>
<!-- 根据查询所有账户 -->
<select id="findAll" resultMap="userAccountMap">
SELECT * FROM account
</select>
### #{}和${}的区别
- #会进行预编译处理,能防止sql注入问题;$是直接替换字符串,有注入问题
- #相当于PreparedStatement处理,$相当于Statement处理
- #对应的变量会自动加上单引号,$不会
## 模糊查询
`concat('%',#{xxx},'%')`
### 在mapper中如何传递多个参数
1. #{0} #{1}
2. 使用`@Param("xxx")`参数,直接写参数名`xxx` ***
3. 使用Map传递
4. 使用javabean传递 ***
## 如何批量执行
1. 使用foreach,主要用在
`insert into tableA value (1,11),(2,22) `
2. 自己创建sqlSessionFactory.openSession(ExecuteType.BATCH)
## java bean的属性和数据库表字段不匹配如何解决?
1. 使用as进行转换:select a_b as ab ...
2. 使用ResultMap
```xml
<ResultMap>
<result property="ab" column="a_b"></result>
</ResultMap>
区分是 namespace+id进行区分
所以相同namespace的话id不能重复;不同的namespace的话id可以重复
where
if
choose
when
otherwise
foreach
<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 1 = 1
<choose>
<when test="title != null">
and title = #{title}
</when>
<when test="content != null">
and content = #{content}
</when>
<otherwise>
and owner = "owner1"
</otherwise>
</choose>
</select>
OGNL表达式
从sql参数中计算出表达式的值,然后根据表达值进行动态拼接
可以,自定义实现TypeHandler,实现 setParameter
方法和getResult
方法
没使用缓存,分布式环境下会有脏数据的
@SpringBootApplication 包括
@Component一般直接写在类上面,就可以生成一个bean,而有时候你想生成一个第三方代码的对象,又不能在代码上写@Component,可以利用@Bean,此时@Bean对应一个方法,方法都返回对象就是一个bean,而且你可以做一些定制
@Bean则常和@Configuration注解搭配使用:
@Configuration
public class WebSocketConfig {
@Bean
public Student student(){
return new Student();
}
}
比如应用在解决spring session的问题
/** * Spring session 浏览器sessionId与服务器不一致解决方案 */ @Bean public DefaultCookieSerializer getDefaultCookieSerializer() { DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer(); defaultCookieSerializer.setUseBase64Encoding(false); return defaultCookieSerializer; }
以前spring配置是用xml配置,现在是使用java代码来实现之前xml的配置能力 比如生成bean使用注解
减少xml配置,减少xml和java代码的切换,以前生成一个bean,既要xml中配置<bean,又要java中写代码,后期如果删除啥的也要同步
面向对象的配置,你可以去继承一个类,修改一些属性来覆盖之前的bean的一些配置
优先级:4>3>1=2
类似于properties,用来作为配置文件配置一些参数供系统读取
env:
list:
- name: '1001'
type: all
- name: '1003'
type: all
@ImportResource
注解
@ImportResource("classpath:beans.xml")
bootstrap.yml 1.1 由父ApplicationContext加载,先于application.yml加载 1.2 属性不会被覆盖
application.yml 2.1 由applicationContext加载 2.2 内容可以被覆盖,一般应用的配置放在这里,可以被配置中心的配置覆盖
-Dspring.profiles.active=test
---
spring:
profiles: test
server:
port: 8000
---
spring:
profiles: production
server:
port: 80
pebble:
cache: true
另外,java代码都Component和@Configuration也可以使用@Profile
@Configuration
@Profile("production")
public class ProductionConfiguration {
// ...
}
server.port = 9090
springBoot提供的一些现成的endpoint,用来分析、监控当前应用的信息,健康情况等
management:
endpoints:
web:
exposure:
include: info, health, env, metrics
@Value("aa.bb")
@ConfiturationProperties
@Configuration
@ConfigurationProperties("storage.local")
public class StorageConfiguration {
...
}
spring模块,主要用来进行数据库访问,也包括Nosql服务访问
比如spring-data-redis、spring-data-es
基于java的模板引擎
比如我们用来做邮件模板,邮件的模板是固定的,但是有一些数据是动态的,可以通过freeMarker加载模板,同时动态传入参数,最后渲染出来静态html
https://www.liaoxuefeng.com/wiki/1252599548343744/1282388443267106
消息通信服务器 依赖zookeeper
生成可视化api文档
我理解就是springBoot提供的对于某个功能的封装打包;
比如spring-boot-starter-data-redis就是提供redis访问的一些能力;
starter的特点是:
spring-cloud-starter-openfeign
spring-cloud-starter-netflix-eureka-client
spring-cloud-starter-config
spring-boot-starter-actuator
spring-boot-starter-aop
spring-boot-starter
spring-boot-starter-web
spring-boot-starter-data-redis
spring-cloud-starter-zipkin
mybatis-spring-boot-starter
spring-boot-starter-freemarker
整合依赖关系(继承自 spring-boot-dependencies
)
定义编码为utf-8
指定jdk版本为jdk1.8
<properties>
<java.version>1.8</java.version>
<resource.delimiter>@</resource.delimiter>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
自动化的资源过滤,
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/application*.yml</include>
<include>**/application*.yaml</include>
<include>**/application*.properties</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<excludes>
<exclude>**/application*.yml</exclude>
<exclude>**/application*.yaml</exclude>
<exclude>**/application*.properties</exclude>
</excludes>
</resource>
</resources>
自动化的插件管理
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>${start-class}</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
不需要,内置了tomcat\jetty容器
实现一个ControllerAdvice类,定义ExceptionHandler来处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler()
@ResponseBody
String handleException(Exception e){
return "Exception Deal! " + e.getMessage();
}
}
redis
quartz定时器
2.1 SimpleTrigger
定时器开始时间、结束时间、多久执行一次、执行多少次停止
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
.usingJobData("trigger1", "这是jobDetail1的trigger")
.startNow()//立即生效
.startAt(startDate)
.endAt(endDate)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)//每隔1s执行一次
.repeatForever())
.build();//一直执行
2.2 CronTrigger
每天几点定时执行
0 0 2 * * ?
每天2点定时执行
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
.usingJobData("trigger1", "这是jobDetail1的trigger")
.startNow()//立即生效
.startAt(startDate)
.endAt(endDate)
.withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018"))
.build();
用来将job和trigger关联起来,并且可以启动和停止定时器
//4、执行
scheduler.scheduleJob(jobDetail, cronTrigger);
scheduler.start();
```java
// 暂停触发器的计时
scheduler.pauseTrigger(trigger.getKey());
// 移除触发器中的任务
scheduler.unscheduleJob(trigger.getKey());
// 删除任务
scheduler.deleteJob(jobDetail.getKey());
* 注意JobDetail和Trigger是org.quartz包下的,不是spring包下的,不要导入错误
*/
@Configuration
public class QuartzConfig {
@Bean
public JobDetail jobDetail() {
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("start_of_day", "start_of_day")
.storeDurably()
.build();
return jobDetail;
}
@Bean
public Trigger trigger() {
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail())
.withIdentity("start_of_day", "start_of_day")
.startNow()
// 每天0点执行
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?"))
.build();
return trigger;
}
}
import org.quartz.JobExecutionContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class HelloJob extends QuartzJobBean
{
@Override
protected void executeInternal(JobExecutionContext context)
{
System.out.println("hello: " + new Date());
}
}
1.qrtz_blob_triggers 2.qrtz_cron_triggers -- cron类型的trigger 3.qrtz_simple_triggers --simple类型的trigger 4.qrtz_simprop_triggers 5.qrtz_fired_triggers --正在运行的trigger,跑完会删除 6.qrtz_triggers 7.qrtz_job_details --job的具体信息 8.qrtz_calendars 9.qrtz_paused_trigger_grps 10.qrtz_scheduler_state --scheduler的状态表 11.qrtz_locks
1,2级缓存用来解决:循环依赖
3级缓存用来优化aop代理可能会生成代理对象
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
...
// 从上至下 分表代表这“三级缓存”
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
...
/** Names of beans that are currently in creation. */
// 这个缓存也十分重要:它表示bean创建过程中都会在里面呆着~
// 它在Bean开始创建时放值,创建完成时会将其移出~
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** Names of beans that have already been created at least once. */
// 当这个Bean被创建完成后,会标记为这个 注意:这里是set集合 不会重复
// 至少被创建了一次的 都会放进这里~~~~
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
}
spring的循环依赖只有当
如果是构造器注入、或者不是单例模式的情况下,会出现异常
构造器注入或者prototype类型的属性注入,都会导致Bean创建失败
> spring题
为啥要使用spring/spring mvc
aop面向切面编程
传统的oop面向对象编程,三个特性:封装、继承、多态性,一般我们处理具体业务
但是,如果我们想加入一些功能,比如调用方法前后打印日志,或者是事务管理等,这种代码的特点是:它会遍布在我们代码的各个地方,同时跟业务没有强相关。
AOP的几个控制点
基本概念
切入点 pointcut
通知 Advice
切面:切入点 + 通知
织入:把切面加入到对象,并创建出代理对象的过程(由spring完成)
另
@Before
前置通知,在连接点方法前调用@Around
环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法,后面会讲@After
后置通知,在连接点方法后调用@AfterReturning
返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常@AfterThrowing
异常通知,当连接点方法异常时调用控制反转IOC
以前,有个A类想调用B类的方法,那A要自己去创建B都实例,比如每次调用前new B出来然后在调用,甚至是单例模式去创建B出来;
spring通过IOC容器功能,现在A想调用B类,就只要
Autowired B b
就可以了,此时A类只要告诉spring它要调用B,B的创建时由spring来控制的spring常见的注入方法
spring中的bean是否线程安全?
我理解sping本身是没有直接提供线程安全保证的;
这个问题要具体分析:
比如
spring 事务实现方式有哪些?
spring事务失效场景
1. @Transtional加在非public方法上
2. final方法
}
修复方法是
public void save(User user) { queryData1(); queryData2(); serviceB.doSave(user); } }
@Servcie public class ServiceB {
}
4. 异常被吃了
5. 异常类型不匹配
比如Transactional默认异常我RuntimeException,但是代码里我们抛出了其他的异常
此时需要人为指定异常
spring 的事务隔离?
使用的默认值,应该是
使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是:
READ_COMMITTED
spring mv的请求过程
@Import的作用
1. import另一个Configuration
2. 直接引入另一个Bean
3. 指定实现ImportSelector
...没咋用过...