2017网站开发合同下载,花生壳怎么建设购物网站,深圳seo网络推广营销,怎么申请pc网站域名一、前言 如果做支付系统或者积分系统我们都知道#xff0c;里面的数字类型和计算规则是我们平时需要注意的。
如金钱的数据类型#xff0c;金钱的加减乘除#xff0c;积分的数目#xff0c;积分的计算规则等等。比如商城的页面金额0.01元#xff0c;是否我们数据库里就是…一、前言 如果做支付系统或者积分系统我们都知道里面的数字类型和计算规则是我们平时需要注意的。
如金钱的数据类型金钱的加减乘除积分的数目积分的计算规则等等。比如商城的页面金额0.01元是否我们数据库里就是存储的是0.01呢有时候我们也碰到过0.0001元的那么在JAVA系统里怎么处理这些数据类型下面根据实践经验进行简单的总结。
二、数据类型
1、积分数量我们可以用Long类型去表示如果使用Integer类型可能不够。
2、金额的页面类型我们可以使用BigDecimal去表示 这里特别需要注意的事BigDecimal的加减乘除
在Java中BigDecimal的加减乘除运算需通过add()、subtract()、multiply()和divide()方法实现直接使用算术运算符会导致精度丢失或计算错误。
1加法使用add()方法。
BigDecimal num1 new BigDecimal(2);
BigDecimal num2 new BigDecimal(6);
BigDecimal sum num1.add(num2); // 结果82减法使用subtract()方法。
BigDecimal difference num2.subtract(num1); // 结果4
BigDecimal difference num2.subtract(num1); // 结果43乘法使用multiply()方法。
BigDecimal product num1.multiply(num2); // 结果124除法使用divide()方法需指定精度和舍入模式
BigDecimal quotient num2.divide(num1, 2, RoundingMode.HALF_UP); // 结果3.00注意事项
构造方法选择优先使用String参数构造避免double参数导致精度问题
// 正确示例
new BigDecimal(0.1); // 精确
// 错误示例
new BigDecimal(0.1); // 存在精度误差使用Hutool工具类库运算BigDecimal的加减乘除、保留两位小数。 Test
public void operationBigDecimal()
{BigDecimal bigDecimal1 new BigDecimal(10.2567);BigDecimal bigDecimal2 new BigDecimal(2.236);//加法BigDecimal addResult NumberUtil.add(bigDecimal1,bigDecimal2);System.out.println(加法运算结果 addResult);//减法BigDecimal subResult NumberUtil.sub(bigDecimal1,bigDecimal2);System.out.println(减法运算结果 subResult);//乘法BigDecimal mulResult NumberUtil.mul(bigDecimal1,bigDecimal2);System.out.println(乘法运算结果 mulResult);//除法BigDecimal divResult NumberUtil.div(bigDecimal1,bigDecimal2);System.out.println(除法运算结果 divResult);//保留两位小数BigDecimal roundResult NumberUtil.round(bigDecimal1,2);System.out.println(保留两位小数 roundResult);
}
BigDecimal的四舍五入并保留两位小数。 Test
public void roundTest()
{BigDecimal bigDecimal1 new BigDecimal(12.233);BigDecimal bigDecimal2 new BigDecimal(12.288);//四舍五入并保留两位小数BigDecimal round1 bigDecimal1.setScale(2, BigDecimal.ROUND_HALF_UP);BigDecimal round2 bigDecimal2.setScale(2, BigDecimal.ROUND_HALF_UP);System.out.println(数值1 bigDecimal1);System.out.println(四舍五入 round1);System.out.println(-----------------);System.out.println(数值2 bigDecimal2);System.out.println(四舍五入 round2);
}
如果是互联网金融行业所有在进行计算的时候尽量使用 ROUND_HALF_EVEN
以上都是页面的数据类型
在数据库里我们可以通过存Long类型单位是 毫来存储金额
三、处理订单的时候我们往往经常需要一个唯一的订单号和交易流水号怎么生成这两个号码更好
博主建议使用雪花算法就行上一节里面写有使用雪花算法注意使用每台部署的服务器标识就是生成以防生成号码重复
package cn.ctg.zlt.framework.common.util.string;import lombok.Data;
import org.springframework.context.annotation.Configuration;/*** ClassName SnowflakeIdWorker* Description TODO* Author jiwenjian* Date 2024/8/13 下午3:55*/
Configuration
Data
public class SnowflakeIdWorkerUtils {/** 工作机器ID(0~31) */private long workerId;/** 数据中心ID(0~31) */private long datacenterId;/** 订单支付单号 1开头 */private static final String PAY_CODE 1;/** 订单退款单号 2开头 */private static final String REFUND_CODE 2;/** 云卡充值单号 3开头 */private static final String ACCOUNT_CODE 3;/** 积分批次号 4开头 */private static final String POINT_CODE 4;/** 积分费用入账批次号 5开头 */private static final String POINT_EXPENSE_CODE 5;/** 首次关注公众号发放积分订单号 6开头 */private static final String FIRST_FOLLOW_ISSUE_POINT_CODE 6;/** 新用户注册发放积分订单号 7开头 */private static final String ISSUE_REGISTER_TASK_POINT_CODE 7;// Fields/** 开始时间截 (2015-01-01) */private final long twepoch 1420041600000L;/** 机器id所占的位数 */private final long workerIdBits 5L;/** 数据标识id所占的位数 */private final long datacenterIdBits 5L;/** 支持的最大机器id结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */private final long maxWorkerId -1L ^ (-1L workerIdBits);/** 支持的最大数据标识id结果是31 */private final long maxDatacenterId -1L ^ (-1L datacenterIdBits);/** 序列在id中占的位数 */private final long sequenceBits 12L;/** 机器ID向左移12位 */private final long workerIdShift sequenceBits;/** 数据标识id向左移17位(125) */private final long datacenterIdShift sequenceBits workerIdBits;/** 时间截向左移22位(5512) */private final long timestampLeftShift sequenceBits workerIdBits datacenterIdBits;/** 生成序列的掩码这里为4095 (0b1111111111110xfff4095) */private final long sequenceMask -1L ^ (-1L sequenceBits);/** 毫秒内序列(0~4095) */private long sequence 0L;/** 上次生成ID的时间截 */private long lastTimestamp -1L;//Constructors/*** 构造函数*/public SnowflakeIdWorkerUtils() {}/*** 支付单号* return*/public String getOrderNo() {return PAY_CODE nextId();}/*** 退款单号* return*/public String getRefundCode() {return REFUND_CODE nextId();}/*** 云卡充值单号* return*/public String getAccountCode() {return ACCOUNT_CODE nextId();}/*** 积分批次号* return*/public String getPointNo() {return POINT_CODE nextId();}/*** 积分费用入账批次号* return*/public String getPointExpenseNo() {return POINT_EXPENSE_CODE nextId();}/*** 首次关注公众号发放积分订单号* return*/public String getFirstFollowIssuePointNo() {return FIRST_FOLLOW_ISSUE_POINT_CODE nextId();}/*** 新用户注册发放积分订单号* return*/public String getIssueRegisterTaskPointNo() {return ISSUE_REGISTER_TASK_POINT_CODE nextId();}/*** 构造函数* param workerId 工作ID (0~31)* param datacenterId 数据中心ID (0~31)*/public SnowflakeIdWorkerUtils(long workerId, long datacenterId) {if (workerId maxWorkerId || workerId 0) {throw new IllegalArgumentException(String.format(worker Id cant be greater than %d or less than 0, maxWorkerId));}if (datacenterId maxDatacenterId || datacenterId 0) {throw new IllegalArgumentException(String.format(datacenter Id cant be greater than %d or less than 0, maxDatacenterId));}this.workerId workerId;this.datacenterId datacenterId;}// Methods/*** 获得下一个ID (该方法是线程安全的)* return SnowflakeId*/public synchronized long nextId() {long timestamp timeGen();//如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过这个时候应当抛出异常if (timestamp lastTimestamp) {throw new RuntimeException(String.format(Clock moved backwards. Refusing to generate id for %d milliseconds, lastTimestamp - timestamp));}//如果是同一时间生成的则进行毫秒内序列if (lastTimestamp timestamp) {sequence (sequence 1) sequenceMask;//毫秒内序列溢出if (sequence 0) {//阻塞到下一个毫秒,获得新的时间戳timestamp tilNextMillis(lastTimestamp);}}//时间戳改变毫秒内序列重置else {sequence 0L;}//上次生成ID的时间截lastTimestamp timestamp;//移位并通过或运算拼到一起组成64位的IDreturn ((timestamp - twepoch) timestampLeftShift) //| (datacenterId datacenterIdShift) //| (workerId workerIdShift) //| sequence;}/*** 阻塞到下一个毫秒直到获得新的时间戳* param lastTimestamp 上次生成ID的时间截* return 当前时间戳*/protected long tilNextMillis(long lastTimestamp) {long timestamp timeGen();while (timestamp lastTimestamp) {timestamp timeGen();}return timestamp;}/*** 返回以毫秒为单位的当前时间* return 当前时间(毫秒)*/protected long timeGen() {return System.currentTimeMillis();}//Test/** 测试 */public static void main(String[] args) {SnowflakeIdWorkerUtils idWorker new SnowflakeIdWorkerUtils(1, 1);for (int i 0; i 10; i) {String id idWorker.getPointNo();System.out.println(id);}}
}