要完成上述需求,需要分两步操作
- 获取resources目录下的sql脚本文件
- 执行该文件
获取resources目录下的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的根路径
执行该sql文件
使用 Spring 提供的工具类执行 sql 文件
我是通过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方式执行 sql 文件
使用的是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(); } } }
jpa方式完整代码
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>