1.需求:为了实现分表操作,我们所有的数据库创建的时候需要根据operatorId进行分表,所以每次创建一个operator时就需要创建一系列属于该operator的表,就是在表名的后面动态的拼接上operatorId
2.解决办法: 首先,我们需要一个sql模板,模板里面都是建库语句,只是在每个表名的后面加上了一个标志符号#
然后我用operatorId去动态的替换该符号,然后再java代码里执行该sql脚本
测试方法:
@Value("${properties_name}")
private String dbPropertiesName;
@PostMapping(value = "/test")
public void test(){
System.out.println("---------------");
try {
replacTextContent("qudao.sql","1");
run("1");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void replacTextContent(String path,String operatorId) throws IOException{
//原有的内容
String srcStr = "#";
//要替换的内容
String replaceStr = operatorId;
String newFileName = "F:/qudao_"+operatorId+".sql";
// 读
Resource resource = new ClassPathResource(path);
File sourceFile = resource.getFile();
FileReader in = new FileReader(sourceFile);
BufferedReader bufIn = new BufferedReader(in);
// 内存流, 作为临时流
CharArrayWriter tempStream = new CharArrayWriter();
// 替换
String line = null;
while ( (line = bufIn.readLine()) != null) {
// 替换每行中, 符合条件的字符串
line = line.replaceAll(srcStr, replaceStr);
// 将该行写入内存
tempStream.write(line);
// 添加换行符
tempStream.append(System.getProperty("line.separator"));
}
// 关闭 输入流
bufIn.close();
// 将内存中的流 写入 文件
FileWriter out = new FileWriter(newFileName);
tempStream.writeTo(out);
out.close();
System.out.println("====path:"+path);
}
public void run(String operatorId) {
try {
// 获取数据库相关配置信息
Properties props = Resources.getResourceAsProperties(dbPropertiesName);
// jdbc 连接信息: 注: 现在版本的JDBC不需要配置driver,因为不需要Class.forName手动加载驱动
String url = props.getProperty("spring.datasource.url");
String username = props.getProperty("spring.datasource.username");
String password = props.getProperty("spring.datasource.password");
// 建立连接
Connection conn = DriverManager.getConnection(url, username, password);
// 创建ScriptRunner,用于执行SQL脚本
ScriptRunner runner = new ScriptRunner(conn);
runner.setErrorLogWriter(null);
runner.setLogWriter(null);
// 绝对路径读取
Reader read = new FileReader(new File("F:/qudao_" + operatorId + ".sql"));
//相对路径读取
//Reader read = Resources.getResourceAsReader("F:/qudao_" + operatorId + ".sql");
// 执行SQL脚本
runner.runScript(read);
// 关闭连接
conn.close();
// 若成功,打印提示信息
System.out.println("====== SUCCESS ======");
} catch (IOException | SQLException e) {
e.printStackTrace();
}
}
特别注意的是:这里最坑的就是文件位置,我的sql模板是放在resources目录下的,采用上面这种读取文件方式也是因为考虑文件的相对路径而采用的,可能细心的人就发现,为什么我的输出却是写死的绝对路径,而不是相对路径,如果直接输出到resources目录下某个sql文件夹中不是更好嘛,不,我试了很久,都没有成功,于是采用这种绝对地址方式,当然,这是本地测试,如果是服务器上,建议使用OSS
下面是采用oss的方式,说白了就是上面的方法的一种改进,原理是:将文件的模板替换后形成流,直接执行流(就是sql脚本流),然后不用生成文件就直接可以执行,且不会破坏模板,模板也不放在项目中,直接放在阿里云上
下面是代码实现:
@Autowired
private ApplicationContext applicationContext ;
@Value("${ykc.oss.url}")
private String ykcOssUrl;
@Value("${ykc.oss.name}")
private String ykcOssName;
@Value("${ykc.oss.keyId}")
private String ykcOssKeyId;
@Value("${ykc.oss.accessKey}")
private String ykcOssAccessKey;
@Value("${ykc.oss.fileName}")
private String ykcOssFileName;```
public void runSql(String replaceStr) {
long start = System.currentTimeMillis();
Connection conn = null;
try{
DataSource dataSource =(DataSource) applicationContext.getBean("dataSource");
conn = (Connection) dataSource.getConnection();
System.out.print("--------:"+conn);
}catch (Exception e){
}
InputStream is;
try {
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(ykcOssUrl, ykcOssKeyId, ykcOssAccessKey);
try {
Date expiration = new Date(System.currentTimeMillis() + 1000 * 1000);
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(ykcOssName, ykcOssFileName, HttpMethod.GET);
// 设置过期时间。
request.setExpiration(expiration);
// 生成签名URL(HTTP GET请求)。
URL signedUrl = ossClient.generatePresignedUrl(request);
// 使用签名URL发送请求。
Map<String, String> customHeaders = new HashMap<>(1);
// 添加GetObject请求头。
is = ossClient.getObject(signedUrl, customHeaders).getObjectContent();
} finally {
}
//原有的内容
String srcStr = "10087";
//要替换的内容
CharArrayWriter tempStream = new CharArrayWriter();
// 创建ScriptRunner,用于执行SQL脚本
ScriptRunner runner = new ScriptRunner(conn);
runner.setErrorLogWriter(null);
runner.setLogWriter(null);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(is));
try {
// 替换
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// 替换每行中, 符合条件的字符串
line = line.replaceAll(srcStr, replaceStr);
// 将该行写入内存
tempStream.write(line);
// 添加换行符
tempStream.append(System.getProperty("line.separator"));
}
// 关闭 输入流
}catch (Exception e){
log.error("流的替换时出现异常,异常信息为:{}",e);
}finally {
}
char[] s = tempStream.toCharArray();
CharArrayReader charArrayReader = new CharArrayReader(s);
Reader read = charArrayReader;
// 执行SQL脚本
runner.runScript(read);
// Reader read = new InputStreamReader(is);
// 关闭连接
conn.close();
// 若成功,打印提示信息
long end = System.currentTimeMillis();
long result = end - start;
log.info("====== SUCCESS ======:"+result);
ossClient.shutdown();
} catch ( Exception e) {
log.error("异常信息为:{}", e);
}
}
当然配置文件里得配置相关oss的地址等
#============== oss ===================
ykc.oss.url=https://oss.aliyuncs.com
#内网地址(开发环境)
ykc.oss.name=wtayvyzzmyanm9vx-user-test
#外网(测试环境等其他环境)
#ykc.oss.name=wtayvyzzmyanm9vx-user-test
ykc.oss.keyId=WTAyVyzZmYaNM9Vx
ykc.oss.accessKey=Us8TMYlwDhPUrAuKh7q3KU5Yqh7hQi
ykc.oss.fileName=qudao.sql
说到这,补充一下,第一种方式里面有一个创建数据库连接,这种方式效率其实比较低效,因为在springboot项目里其实已经连接过了,直接注入
@Autowired
private ApplicationContext applicationContext ;
就可以获取到连接,所以这样写是比较简单的(推荐)
版权声明:本文为weixin_43931650原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。