启动
WARNING : Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package.
解决:根据提示,SpringBoot启动类放置目录不正确,报该错时,我的启动类是直接放在java路径下,没有放在程序根包下。
错误示例:- 正确示例
应用打包成war包,部署到tomcat中,发现应用没用启动
解决:启动类继承SpringBootServletInitializer
public class XxxApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(XxxApplication.class,args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(XxxApplication.class);
}
}
动态数据源
- 错误描述:
The dependencies of some of the beans in the application context form a cycle:
scheduleJobLogService (field protected com.baomidou.mybatisplus.mapper.BaseMapper com.baomidou.mybatisplus.service.impl.ServiceImpl.baseMapper)
↓
scheduleJobLogDao defined in file [E:\xxxx\modules\job\dao\ScheduleJobLogDao.class]
↓
sqlSessionFactory defined in class path resource [com/baomidou/mybatisplus/spring/boot/starter/MybatisPlusAutoConfiguration.class]
┌─────┐
| dataSource defined in class path resource [io/xxx/datasources/DynamicDataSourceConfig.class]
↑ ↓
| firstDataSource defined in class path resource [io/xxx/datasources/DynamicDataSourceConfig.class]
↑ ↓
| org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker
└─────┘
- 解决:
项目中配置了动态数据源,但在启动时报了以上错误,根据提示可知,dataSource注入时出现了死循环,一开始是自定义的dataSource(DynamicDataSource),后续又变成了默认的dataSource(org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker),系统存在两个dataSource。所以我们需要去掉默认的DataSource,改为自定义DataSource,以下是具体代码:
package io.xxx;
import io.xxx.datasources.DynamicDataSourceConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Import;
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@Import({DynamicDataSourceConfig.class})
public class XxxApplication {
public static void main(String args[]) {
SpringApplication.run(XxxApplication.class,args);
}
}
事务回滚
当程序出现异常时,为了避免数据的不一致性,我们需要进行事务的回滚。所以在讲事务回滚之前我们先来看下Java的异常体系。
图片转载自关于异常体系的解释,读者可点击该链接阅读。
Error是我们无法通过修改程序来解决的异常,比如OutOfMemoryError、ThreadDeath,当这种异常发生时,线程会直接终止;Exception是我们程序编写不当导致的异常,比如空指针,出现该异常时,程序不会终止,而是继续运行下去。
异常分类:
我们可以将异常分为运行时异常(RuntimeException)和非运行时异常(Exception中除了RuntimeException及其子类以外的)。另一方面,我们可以将异常分为受控异常(checked exceptions)和不受控异常(unchecked exceptions)。
1、受控异常(checked exceptions):就是非运行时异常,即Exception中除了RuntimeException及其子类以外的。
2、不受控异常(unchecked exceptions):RuntimeException和Error。
@Transaction实战遇到的问题
我在将该注解添加Service中的一个方法时,发现程序即使出现异常也没有回滚,后来查了几篇文章,讲到Spring默认的事务异常处理机制是:
Spring框架的事务管理默认地只在发生不受控异常时才进行事务回滚。
若程序Catch住了异常,并且没有往外抛,那么该事务不会进行回滚
遇到这种情况,我们可以通过以下两种方式解决:
1、在类或方法前注解配置@Transactional(rollbackFor=Exception.class)
2、在catch中手动进行回滚,添加如下代码:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
笔者在使用第2种方法时,程序报了以下错误
org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope异常处理
根据提示,说当前方法没有开启事务,很奇怪,方法上明明加了@Transaction注解,为啥还提示没有加。仔细看了下代码,发现我的这个方法不是直接被外层调用的,外层是先调用了该方法所在类的A方法,然后A方法调用的它,而A方法并没有开启事务。 将A方法添加@Transaction之后,程序可以正常运行了,事务也可以正常回滚。
第三方集成
Mybatis
- 错误描述:
Caused by: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): io.xxx.modules.xxx.dao.XxxDao.queryList
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:227) ~[mybatis-3.4.6.jar:3.4.6]
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:49) ~[mybatis-3.4.6.jar:3.4.6]
at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65) ~[mybatis-3.4.6.jar:3.4.6]
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58) ~[mybatis-3.4.6.jar:3.4.6]
at com.sun.proxy.$Proxy83.queryItfAdvancePaymentList(Unknown Source) ~[na:na]
- 解决:
提示xml文件中没有queryList这个sql,但文件实际是有的,为何找不到呢?网上提供了几种排查方法,我现在简单罗列一下:
- xml文件中的 namespace=“xxx.xxx.xxx.Dao” 中的路径是否与接口文件路径一致。
- parameterType类型 与 resultType类型是否与接口文件中定义的类型一致。
- xml文件扫描路径是否配置正确,否则xml文件无法被扫描到。
经过上面的排查,我这边问题依旧存在,但上面的排查给了我大体思路:首先,保证自己的xml文件放置的路径正确;其次,保证xml文件和接口文件中的方法名、参数及返回类型匹配。然后按照这两步骤,发现自己的xml文件放置的文件夹在编译之后没有在扫描路径下,如图:
造成上述现象是由于Intellj Idea的显示模式设置造成的,如图
如果一个文件夹下面只有一个文件的话,子文件夹会和父文件夹连接显示,比如mapper.job,如果要建job的同级目录的话只能选中mapper的父文件夹resources,然后新建mapper.realTime文件夹,但这样子建出来的realTime文件夹其实不在mapper下面,因为它实际的名字叫mapper.realTime文件夹。为了避免此显现,建议将‘Compact Middle Packages’选项取消勾选,这样子目录层级分明,不会出错。下图是取消勾选的效果
- 错误描述:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'names' not found. Available parameters are [collection, list]
- 解决:
因为Mybatis里面用了foreach标签,需要传递一个list进行遍历,如果在dao层方法直接传递list的话就会报该错误,可以在参数名称前加一个注解解决,代码如下:
public List<Object> getSomethings(@Param("names")List names)
当然也可以将List参数封装到Map里面,需要注意的是key一定要与dao文件里面遍历的key一致。
- 错误描述:
mybatis中查询oracle数据库date类型的时间没有时分秒
- 解决措施:
原因出在mybatis中的mapper.xml中对象的属性对应的jdbcType=date。jdbcType=date对应的Java类型是java.sql.date,所以没有时分秒。如果想显示时分秒,对象的属性对应的jdbcType应该设置成TIMESTAMP。
<result column="CREATE_TIME" property="createTime" jdbcType="TIMESTAMP"/>
Quartz
- 错误描述:
Caused by: org.quartz.SchedulerException: ThreadPool class 'org.quartz.simple.SimpleThreadPool' could not be instantiated.
at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:841) ~[quartz-2.3.0.jar:na]
at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1559) ~[quartz-2.3.0.jar:na]
at org.springframework.scheduling.quartz.SchedulerFactoryBean.createScheduler(SchedulerFactoryBean.java:650) ~[spring-context-support-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.scheduling.quartz.SchedulerFactoryBean.prepareScheduler(SchedulerFactoryBean.java:590) ~[spring-context-support-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:490) ~[spring-context-support-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1767) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1704) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
- 解决:
使用Intellij Idea全局搜索SimpleThreadPool这个类,发现其路径为org.quartz.simpl,也就是说simpl后面没有e,好坑的单词。。。
打包
jar包
springboot使用的是maven,通过mvn install
指令执行完毕之后,然后java -jar XXX.jar时,提示没有主清单属性
解决:pom文件需要添加一个插件,如下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
重新执行mvn install
之后,运行jar包,问题解决。