使用 JdbcTemplate 动态创建表并添加数据
Spring JdbcTemplate框架(二)——动态建表
主要思路是:
使用Spring配置JdbcTemplate,通过一个代理对象和数据库进行对应,这个对象除了id和一个tableName属性外和数据库的字段名称都是一致的
通过一个公共方法类来获得代理类有那些属性,用来创建表和新增时进行动态SQL的拼装。核心处理是,先看有么有该表,没有创建插入,有的话直接插入
首先配置Spring
<? xml version="1.0" encoding="UTF-8" ?>
< beans xmlns ="http://HdhCmsTestspringframework.org/schema/beans"
xmlns:xsi ="http://HdhCmsTestw3.org/2001/XMLSchema-instance"
xmlns:aop ="http://HdhCmsTestspringframework.org/schema/aop"
xmlns:tx ="http://HdhCmsTestspringframework.org/schema/tx"
xsi:schemaLocation ="http://HdhCmsTestspringframework.org/schema/beans http://HdhCmsTestspringframework.org/schema/beans/spring-beans-2.0.xsd
http://HdhCmsTestspringframework.org/schema/aop http://HdhCmsTestspringframework.org/schema/aop/spring-aop-2.0.xsd
http://HdhCmsTestspringframework.org/schema/tx http://HdhCmsTestspringframework.org/schema/tx/spring-tx-2.0.xsd" >
<!-- 数据源 -->
< bean id ="dataSource"
class ="org.apache测试数据mons.dbcp.BasicDataSource"
destroy-method ="close" >
< property name ="driverClassName" value ="com.mysql.jdbc.Driver" />
< property name ="url"
value ="jdbc:mysql://192.168.0.69:3306/cui?useUnicode=true&characterEncoding=UTF-8" />
< property name ="username" value ="root" />
< property name ="password" value ="root" />
<!-- 连接池启动时的初始值 -->
< property name ="initialSize" value ="2" />
<!-- 连接池的最大值 -->
< property name ="maxActive" value ="2" />
<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
< property name ="maxIdle" value ="2" />
<!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
< property name ="minIdle" value ="2" />
< property name ="defaultAutoCommit" value ="true" />
</ bean >
<!-- JDBC 操作模板 -->
< bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" >
< constructor-arg >
< ref bean ="dataSource" />
</ constructor-arg >
</ bean >
<!-- 用于初始化获得Spring对象的类 -->
< bean id ="springfactory" class ="com.SpringFactory" ></ bean >
</ beans >
com.SpringFactory对象是用来动态获取Spring管理对象的类,之前博客中提到过:
/**
* 获得Spring管理对象
*/
public class SpringFactory implements ApplicationContextAware {
private static ApplicationContext context;
@SuppressWarnings( "static-access" )
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this .context = applicationContext;
}
public static Object getObject(String id) {
Object object = null ;
object = context.getBean(id);
return object;
}
}
public class ObjectUtil {
/**
* 返回一个对象的属性和属性值
*/
public static Map<String, String> getProperty(Object entity) {
Map <String, String> map = new HashMap<> ();
if (entity == null ) return map;
try {
Class c = entity.getClass();
// 获得对象属性
Field field[] = c.getDeclaredFields();
for (Field f : field) {
f.setAccessible( true );
String fieldName = f.getName();
if ("serialVersionUID".equals(fieldName)) continue ;
Object val = f.get(entity);
map.put(fieldName, val == null ? "" : val.toString());
}
} catch (Exception e) {
throw new ServiceException(e);
}
return map;
}
/**
* 获得对象属性的值
*/
private static Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
Class ownerClass = owner.getClass();
methodName = methodName.substring(0, 1 ).toUpperCase()
+ methodName.substring(1 );
Method method = null ;
try {
method = ownerClass.getMethod("get" + methodName);
} catch (SecurityException e) {
throw new ServiceException(e);
} catch (NoSuchMethodException e) {
throw new ServiceException("can‘t find ‘get" + methodName + "‘ method" );
}
return method.invoke(owner);
}
}
再来看一下对象实体类,要注意这个类一定不要和实际的类混了,因为你的业务对象类中可能会有一些额外的字段,这个会被公共方法的类解析而出问题的
package com;
/**
* @说明 需要操作的实体
* @author cuisuqiang
* @version 1.0
* @since 这个只能是代理对象,也就是说你需要和数据库同步对属性字段,实际上我们在表中还动态添加了一个 tableName 字段
*/
public class Users {
private String userName;
private String userPass;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this .userName = userName;
}
public String getUserPass() {
return userPass;
}
public void setUserPass(String userPass) {
this .userPass = userPass;
}
}
核心处理类
package com;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @说明 进行测试
* @author cuisuqiang
* @version 1.0
* @since
*/
public class DbTest {
private static ApplicationContext context = null ;
public static void main(String[] args) {
context = new ClassPathXmlApplicationContext("applicationContext.xml" );
Users user = new Users();
user.setUserName( "cuisuqinag@163测试数据" );
user.setUserPass( "http://cuisuqiang.iteye测试数据/" );
int re = insertObject("users" ,user);
System.out.println( "---->" + re + "<----" );
}
public static int insertObject(String tableName,Object obj){
int re = 0 ;
try {
JdbcTemplate jt = (JdbcTemplate)context.getBean("jdbcTemplate" );
SimpleDateFormat format = new SimpleDateFormat("yyyy_MM" );
String tname = tableName + "_" + format.format( new Date());
// 如果有某表
if (getAllTableName(jt,tname)){
// 保存数据
re = saveObj(jt,tname,obj);
} else {
// 动态创建表
re = createTable(jt,tname,obj);
// 保存数据
re = saveObj(jt,tname,obj);
}
} catch (Exception e) {
e.printStackTrace();
}
return re;
}
/**
* 保存方法,注意这里传递的是实际的表的名称
*/
public static int saveObj(JdbcTemplate jt,String tableName,Object obj){
int re = 0 ;
try {
String sql = " insert into " + tableName + " (" ;
Map <String,String> map = ObjectUtil.getProperty(obj);
Set <String> set = map.keySet();
for (String key : set){
sql += (key + "," );
}
sql += " tableName ) " ;
sql += " values ( " ;
for (String key : set){
sql += ("‘" + map.get(key) + "‘," );
}
sql += ("‘" + tableName + "‘ ) " );
re = jt.update(sql);
} catch (Exception e) {
e.printStackTrace();
}
return re;
}
/**
* 根据表名称创建一张表
* @param tableName
*/
public static int createTable(JdbcTemplate jt,String tableName,Object obj){
StringBuffer sb = new StringBuffer("" );
sb.append( "CREATE TABLE `" + tableName + "` (" );
sb.append( " `id` int(11) NOT NULL AUTO_INCREMENT," );
Map <String,String> map = ObjectUtil.getProperty(obj);
Set <String> set = map.keySet();
for (String key : set){
sb.append( "`" + key + "` varchar(255) DEFAULT ‘‘," );
}
sb.append( " `tableName` varchar(255) DEFAULT ‘‘," );
sb.append( " PRIMARY KEY (`id`)" );
sb.append( ") ENGINE=InnoDB DEFAULT CHARSET=utf8;" );
try {
jt.update(sb.toString());
return 1 ;
} catch (Exception e) {
e.printStackTrace();
}
return 0 ;
}
/**
* 查询数据库是否有某表
* @param cnn
* @param tableName
* @return
* @throws Exception
*/
@SuppressWarnings( "unchecked" )
public static boolean getAllTableName(JdbcTemplate jt,String tableName) throws Exception {
Connection conn = jt.getDataSource().getConnection();
ResultSet tabs = null ;
try {
DatabaseMetaData dbMetaData = conn.getMetaData();
String[] types = { "TABLE" };
tabs = dbMetaData.getTables( null , null , tableName, types);
if (tabs.next()) {
return true ;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
tabs.close();
conn.close();
}
return false ;
}
}
动态检查是否有某表和动态创建表之前博客有提到,最主要的就是根据对象属性Map进行动态SQL拼装
但是这里这个方法有很多的限制,比如创建字段的长度,新增时字段就必须有值,因为动态SQL会进行全量字段插入
另外,新增的字段表的名称是为了之后删除和查询详细做准备的。
注意这是一个系列的文章,注意前后几篇文章。
2、Hibernate动态创建表 <--返回目录
Spring Data JPA/Hibernate 运行期动态模型、动态实体建表、动态字段查询的方式
最近公司的零代码开发平台数据中心需要重构,需要在页面上创建表模型添加修改字段。涉及到动态生成表结构,动态生成模型实体类动态查询表字段等等,经过调研发现hibernate在这方面是很方便的,调用内置API就能完成系列操作,下面贴出核心代码:
public class DynamicDdlTest {
@Autowired
private EntityManagerFactory entityManagerFactory;
/**
* 运行期的持久化实体没有必要一定表示为像POJO类或JavaBean对象那样的形式。
* Hibernate也支持动态模型在运行期使用Map)和象DOM4J的树模型那样的实体表示。
* 使用这种方法,你不用写持久化类,只写映射文件就行了。
* */
public static final String XML_MAPPING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE hibernate-mapping PUBLIC\n" +
" \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"\n" +
" \"http://HdhCmsTesthibernate.org/dtd/hibernate-mapping-3.0.dtd\">\n" +
"<hibernate-mapping>\n" +
" <class entity-name=\"Student\" table=\"t_student\">\n" +
" <id name=\"id\" type=\"java.lang.Long\" length=\"64\" unsaved-value=\"null\">\n" +
" <generator class=\"identity\" />\n" +
" </id>" +
" <property type=\"java.lang.String\" name=\"username\" column=\"username\"/>\n" +
" <property name=\"password\" type=\"java.lang.String\" column=\"password\"/>\n" +
" <property name=\"sex\" type=\"java.lang.String\" column=\"sex\"/>\n" +
" <property name=\"age\" type=\"java.lang.Integer\" column=\"age\"/>\n" +
" <property name=\"birthday\" type=\"java.util.Date\" column=\"birthday\"/>\n" +
" </class>" +
"</hibernate-mapping>" ;
@Test
public void testDynamicDdl() {
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory. class );
StandardServiceRegistry serviceRegistry = sessionFactory.getSessionFactoryOptions().getServiceRegistry();
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
sessionFactory.getSessionFactoryOptions();
// 读取映射文件
metadataSources.addInputStream( new ByteArrayInputStream(XML_MAPPING.getBytes()));
Metadata metadata = metadataSources.buildMetadata();
// 创建数据库Schema,如果不存在就创建表,存在就更新字段,不会影响已有数据
SchemaExport schemaExport = new SchemaExport();
schemaExport.createOnly(EnumSet.of(TargetType.DATABASE), metadata);
Metadata metadata = metadataSources.buildMetadata();
// 创建会话工厂
SessionFactory newSessionFactory = metadata.buildSessionFactory();
// 保存对象
Session newSession = newSessionFactory.openSession();
for ( int i = 0; i < 100; i++ ) {
Map <String, Object> student = new HashMap<> ();
student.put( "username", "张三" + i);
student.put( "password", "adsfwr" + i);
student.put( "sex", i % 2 == 0 ? "male" : "female" );
student.put( "age" , i);
student.put( "birthday", new Date());
newSession.save( "Student" , student);
}
// 查询所有对象
Query query = newSession.createQuery("from Student" );
List list = query.getResultList();
System.out.println( "resultList: " + list);
// 关闭会话
newSession.close();
}
}
其他
1)SpringBoot下Java动态创建表和表字段
---
JdbcTemplate或hibernate动态建表
标签:cee unicode relevant 高峰 工厂 connect cat 申请 use
查看更多关于JdbcTemplate或hibernate动态建表的详细内容...