BatchSaveUtils.java 4.55 KB
package com.bsth.util;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @ClassName: BatchSaveUtils 
 * @Description: TODO(批量持久化工具类) 
 * @author PanZhao
 * @date 2016年6月14日 上午10:21:53 
 *
 */
public class BatchSaveUtils<T> {
	
	private static String driver;
	private static String url;
	private static String uname;
	private static String pwd;
	
	final static int batchSize = 5000;
	
	Logger logger = LoggerFactory.getLogger(this.getClass());
	
	static {
		driver = ConfigUtil.get("spring.datasource.driver-class-name");
		url = ConfigUtil.get("spring.datasource.url");
		uname = ConfigUtil.get("spring.datasource.username");
		pwd = ConfigUtil.get("spring.datasource.password");
	}
	
	/**
	 * 
	 * @Title: saveListMysql 
	 * @Description: TODO(批量对象入库) 
	 * @param @param list
	 * @param @param clazz
	 * @throws
	 */
	public int saveList(List<T> list, Class<T> clazz){
		//获取泛型 T 的字节码
		Table table = clazz.getAnnotation(Table.class);
		if(null == table){
			logger.error("找不到" + clazz.getSimpleName() + "类的表映射");
			return -1;
		}
		List<Field> fs = fieldFilter(clazz.getDeclaredFields());
		String sql = createSql(table, fs);
		logger.info(sql);
		
		//每5000条批量入库一次
		Connection conn = null;
		PreparedStatement ps = null;
		try{
			conn = getConn();
			conn.setAutoCommit(false);
			ps = conn.prepareStatement(sql);
			
			int fsize = fs.size(), count = 0;
			for(T t : list){
				count ++;
				for(int i = 0; i < fsize; i ++){
					ps.setObject(i + 1, fs.get(i).get(t));
				}
				
				ps.addBatch();
				if(count % batchSize == 0){
					ps.executeBatch();
					conn.commit();
                    ps.clearBatch();
				}
			}
			ps.executeBatch();
			conn.commit();
		}catch(Exception e){
			logger.error("",e);
			return -1;
		}finally {
			closeAll(conn, ps, null);
		}
		
		return 0;
	}
	
	public String createSql(Table table, List<Field> fs){
		String sqlBefore = "insert into " + table.name() + "("
				,sqlValues = " values(";
		for(Field field : fs){
			sqlBefore += (propertyToField(field.getName()) + ",");
			sqlValues += "?,";
		}
		sqlBefore = sqlBefore.substring(0, sqlBefore.length() - 1) + ")";
		sqlValues = sqlValues.substring(0, sqlValues.length() - 1) + ")";
		
		return sqlBefore + " " + sqlValues;
	}
	
	/**
	 * 
	 * @Title: propertyToField 
	 * @Description: TODO(java转数据库字段名) 
	 * @param @param property
	 * @throws
	 */
    public static String propertyToField(String property) {  
        if (null == property) {  
            return "";  
        }  
        char[] chars = property.toCharArray();  
        StringBuffer sb = new StringBuffer();  
        for (char c : chars) {  
            if (CharUtils.isAsciiAlphaUpper(c)) {  
                sb.append("_" + StringUtils.lowerCase(CharUtils.toString(c)));  
            } else {  
                sb.append(c);  
            }  
        }  
        return sb.toString();  
    } 
    
    public static List<Field> fieldFilter(Field[] fields){
    	List<Field> fs = new ArrayList<>();
    	for(Field field : fields){
			field.setAccessible(true);
			//忽略 Transient 字段
			if(field.getAnnotation(Transient.class) != null)
				continue;
			//忽略关联
			if(field.getAnnotation(OneToMany.class) != null
					|| field.getAnnotation(OneToOne.class) != null
					|| field.getAnnotation(ManyToOne.class) != null
					|| field.getAnnotation(ManyToMany.class) != null)
				continue;
			fs.add(field);
		}
    	return fs;
    }
    
	public static Connection getConn() throws Exception{
		Class.forName(driver); 
		Connection conn = DriverManager.getConnection(url,uname,pwd);
		return conn;
	}
	
	public static void closeAll(Connection conn, PreparedStatement ps, ResultSet rs){
		try {
			if(conn != null){
				conn.close();
			}
			if(ps != null){
				ps.close();
			}
			if(rs != null){
				rs.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}