关于保存批量数据进入mysql
提出的要求:
生成13位纯数字的卡号与8位纯数字的卡密,要求卡号与卡密都必须全表唯一,然后保存到mysql。
思路:
1.首先mysql中将这两个字段设置唯一索引,保证这两个字段的值在该表中是唯一存在的
2.卡号是有序增长的,实现比较容易,先查询数据库中该字段的最大值,然后进行增长生成
3.卡密是无序的,实现起来有些困难,(网上查找和经过多次运行结果,发现随机数的重复率是处于最低,所以选定了随机生成),查询数据库中该字段,将该字段放入map中(为了在生成卡密的时候进行判断,该卡密是否存在)每次生成唯一的时候,都会将值放入该map,生成的卡密放入linedklist中(因为这是个频繁的添加操作,linkedlist性能比arraylist性能高)
4.循环遍历卡号(卡号和卡密数量是一样的),然后生成保存的对象,放入list中
5.重新saveAll()方法(因为使用的springdatajpa,该saveAll()源码中是将数据进行循环遍历然后还是一条条的保存,使用了jpa的批量保存配置,设置后与未配置时并没有多少区别),进行保存。
代码:
service层的方法
@PersistenceContext() protected EntityManager entityManager; public List<PayGeneralCard> add(PayGeneralCardFormBean formBean //校验当前spAppId是否时有效期 PayServiceProvider provider = payServiceProviderService.checkSpAppIdAndState(formBean.getSpAppId()); if(null == provider){ return null; } //获取当前应用最大的批次号 int maxBatchNumber = findMaxBatchNumber(formBean.getSpAppId()); //获取最大的卡号 Long byMaxCardNumber = findByMaxCardNumber(); //获取所有卡号,由于是写的sql查询所以数据类型变成了BigInteger,后面会转成Long List<BigInteger> cardPasswordfindAll = payGeneralCardDao.cardPasswordfindAll(); HashMap<String, Boolean> map = new HashMap<>(); List<Long> cardPasswords = cardPasswordfindAll.stream().map(item-> item.longValue()).collect(Collectors.toList()); for(Long cardPassword:cardPasswords){ map.put(cardPassword.toString(),true); } //生成卡号 ArrayList<Long> cardNumbers = PayCardNumberUtil.createNumber(formBean.getCount(), byMaxCardNumber); //生成卡密 LinkedList<Long> passwords = PayCardPassWordUtil.createPassword(formBean.getCount(),map); //组装数据 LinkedList<PayGeneralCard> list = new LinkedList<>(); for(int i = 0;i<cardNumbers.size();i++){ PayGeneralCard bean = createBean(formBean.getSpAppId(), formBean.getType(), cardNumbers.get(i), passwords.get(i), maxBatchNumber); list.add(bean); } //保存数据 List<PayGeneralCard> payGeneralCards = savaAll(list); return payGeneralCards; } //批量添加数据 public List<PayGeneralCard> savaAll(List<PayGeneralCard> payGeneralCards){ ArrayList<PayGeneralCard> list = new ArrayList<>(16); for(PayGeneralCard payGeneralCard : payGeneralCards){ entityManager.persist(payGeneralCard); list.add(payGeneralCard); } return list; }
PayCardNumberUtil
import java.util.ArrayList; public class PayCardNumberUtil { private static long seq = 1000000000000l; private static final long ROTATION = 9999999999999l; public static synchronized long next() { if (seq > ROTATION) seq = 1000000000000l; return seq++; } /** * 生成一卡通卡号的方法 * @param count 生成总数 * @param startNumber 从这个数开始往后生成 * @return */ public static ArrayList<Long> createNumber(long count,long startNumber){ if(seq < startNumber){ seq = startNumber; } ArrayList<Long> list = new ArrayList<>(); for (int i = 0; i < count; i++) { long next = PayCardNumberUtil.next(); list.add(next); } return list; } public static void main(String[] args) { System.out.println(PayCardNumberUtil.createNumber(10l, 2004000000057l)); } }
PayCardPassWordUtil
import java.util.*; /** * 一卡通密码生成器 * * @author nature * @create 2017-12-22 10:58 */ public class PayCardPassWordUtil { public static LinkedList<Long> createPassword(Long count,Map<String, Boolean> map){ LinkedList<Long> list = new LinkedList<>(); for (int i = 0; i < count; i++) { String number = generateUID(map); list.add(Long.parseLong(number)); } return list; } //唯一一个在测试时没有重复项的方法 public static String generateUID(Map<String, Boolean> map){ Random random = new Random(); String result=""; for(int i=0;i<8;i++){ //首字母不能为0 result += (random.nextInt(9)+1); } //如果有值说明改卡密已经存在了,需要重新再生成 if(null != map.get(result)){ return generateUID(map); } map.put(result,true); return result; } public static void main(String[] args) { Map<String, Boolean> map = new HashMap<String, Boolean>(); for (int i = 0; i < 1000; i++) { System.out.println(generateUID(map)); } } }