需求背景简述:springboot-maven项目在运行过程中,需要依据用户的行为来触发数据库建表操作,原来的jpa动态建表已经不能支撑(jpa是在项目启动时动态建表,也可能我没找到项目运行中利用jpa动态建表的用法),所以我选择了去执行sql文件的方法。
一般来说,项目的配置文件及静态资源都会放置在resources目录下。如下图
当需要在java代码中使用resources目录下的文件时,就需要先获取该文件了 以获取上图test.sql文件为例,方法有二
//这种方法在linux下无法工作
File sourceFile = ResourceUtils.getFile("classpath:db/test.sql");
⚠️:这种方法在linux下无法工作,我未采用
我使用的是第二种。
import org.springframework.core.io.Resource;
// ... 忽略部分代码
Resource resource = new ClassPathResource("db/test.sql");
//获取到resource对象后,可以调用resouce.getFile()方法来获取文件。
File sourceFile = resource.getFile();
通过Resouce的实现类ClassPathResource来new一个对象。 该构造方法的参数是resources目录下的文件路径,注意这里是使用的相对路径(相对于resouces目录而言的)
//通过入参相对路径或绝对路径都没有获取成功
Class.getResource("")获取相对于当前类的相对路径
Class.getResource("/")获取classpath的根路径
ClassLoader.getResource("")获取classpath的根路径
我是通过jpa来简化对数据库的操作,所以采用了Spring的工具类;如果用的是mybatis,可以直接跳过看下面
import javax.sql.DataSource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
// ... 忽略部分代码
DataSource dataSource = createDataSource();
Resource resource = new ClassPathResource("db/test.sql");
ScriptUtils.executeSqlScript(dataSource.getConnection(), resource);
使用的是mybatis的ScriptRunner方法
直接上代码
/**
* 使用ScriptRunner执行sql文件
*/
public class ExecuteSql {
@Autowired
private DataSource dataSource; // 获取数据库连接对象
public static void main(String[] args) {
try {
executeSqlFile("db/test.sql");
} catch (Exception e) {
e.printStackTrace();
}
}
private void executeSqlFile(String sqlFileName) throws Exception {
// 获取连接对象
Connection conn = dataSource.getConnection();
//或者直接指明数据库
//Class.forName(className);
//Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
try {
// 设置不自动提交
conn.setAutoCommit(false);
// 初始化ScriptRunner
ScriptRunner runner = new ScriptRunner(conn);
// 设置不自动提交
runner.setAutoCommit(false);
// true,遇见错误会停止执行,打印并抛出异常,捕捉异常,并进行回滚,保证在一个事务内执行;
// false,遇见错误不会停止,会继续执行,会打印异常信息,并不会抛出异常,当前方法无法捕捉异常无法进行回滚操作,无法保证在一个事务内执行;
runner.setStopOnError(true);
// true则获取整个脚本并执行;
// false则按照自定义的分隔符每行执行;
runner.setSendFullScript(false);
// 定义命令间的分隔符
runner.setDelimiter(";");
runner.setFullLineDelimiter(false);
// 设置是否输出日志,null不输出日志,不设置自动将日志输出到控制台
runner.setLogWriter(null);
// 读取文件
Resource resource = new ClassPathResource(sqlFileName);
File file = resource.getFile();
// 如果有多个sql文件,可以写多个runner.runScript(xxx),
runner.runScript(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
// 执行
conn.commit();
} catch (Exception e) {
conn.rollback();
e.printStackTrace();
} finally {
conn.close();
}
}
}
import javax.sql.DataSource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
// 获取连接对象
DataSource dataSource = createDataSource().getConnection();
//也可以下面这种方式直接指明
//Class.forName(className);
//Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
Resource resource = new ClassPathResource("db/test.sql");
ScriptUtils.executeSqlScript(conn, resource);
//去检查数据库验证吧!
如果成功了,那么下面就不用看了
看到有情况是按照上述jpa方式执行了代码,但是仍然有类似找不到文件的报错 如:
java.io.FileNotFoundException: class path resource [db/test.sql] cannot be resolved to URL because it does not exist
at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:195)
ClassPathResource方法是到 classPath* 下去找,然后在项目本地的目录下找classPath下是否有这个文件(maven的classPath在 “target\classes”目录下)
可以检查下pom.xml文件, 可能是springboot的maven默认只加载了classPath同级目录下的文件,想要加载其他文件可以使用配置标签
如下:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
//相对路径
<include>**/*.sql</include>
</includes>
</resource>
</resources>
</build>
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有