精华内容
下载资源
问答
  • 对银行系统的要求
    千次阅读
    2020-12-24 03:16:13

    摘要

    目前,随着移动互联网技术的快速发展,互联网在线金融交易逐渐成为一种流行的趋势。人们通过在在线金融平台上进行交易转账、汇款、账户查询等,进而避免了专门去银行办理相关业务,节省了大量的时间和人力物力。网上银行综合管理系统作为一种能给以相对个性化的表达方式来表达自身情感的平台,也逐渐变得流行起来。

    本文就基于此背景,以满足人们的情感表达为需求,开发出一套个性化的基于B/S模式的网上银行综合管理系统。该系统基于时下流行的Python语言开发,使用Django框架进行基础开发,数据库采用Mysql。 该系统提供的功能也很多,如提供用户注册、用户管理、账户查询、转账记录查询等。本文先本文对网上银行综合管理系统进行整体分析,明确了系统的可行性和用户需求;根据模块化原理,规划设计了系统功能模块;

    在数据库设计部分,详细说明了系统数据库的结构和数据库的完整性、安全性措施;给出了系统架构,接着分析了该系统各部分实现的相关技术原理,程序设计则采用面向对象的程序设计思想,提出系统的程序设计思路,对前台与后台功能的程序实现进行了详细论述;在系统测试时具体分析测试过程中出现的主要问题,并提出了解决方案,最后通过编写代码和相关调试最终完成了整个系统的设计,达到了预期的目的和效果。

    关键词:Python、数据库、网站设计

    2.项目需求分析

    个人网上银行综合管理系统是一个多用户、多界面的系统,基于个人网上银行综合管理系统的特点,本系统实现个人网上银行综合管理系统的主要功能,包括网上银行综合管理系统的用户登录/退出,用户进行账户查询、转账和挂失功能等。网上银行综合管理系统主要区分了两类用户,分别为网上银行综合管理系统管理员和普通用户。网站后台登录仅限于网上银行综合管理系统的系统管理员,普通用户均以普通用户身份访问。普通用户主要的功能是分页、分类、分标签阅读网上银行综合管理系统站主文章和浏览图片,完成交易评论和留言。以上是个人网上银行综合管理系统的系统需求分析的基本实现目标,由于个人网上银行综合管理系统的个性化特点,还应实现网上银行综合管理系统站主自定义网站系统页面的功能,如添加标签栏、归档栏、日历、横幅图片、寄语等包括但不限于此的个性化功能。因此主要包括以下几个模块组成:

    1.前台模块

    本模块主要由登录模块组成,为了保证平台的安全,未登录用户不可以进行任何操作。而对已经登陆的用户,他们可以网上银行综合管理系统内容时行浏览、查阅历史交易记录。也可以通过注册后登录网上银行综合管理系统,对自己的账号进行挂失等基本操作。

    2.用户模块

    本模块主要由个人信息管理、账户状态管理、 交易记录管理等几个部分组成。这些功能可以对用户个人网上银行综合管理系统中的个人信息和交易记录进行设置和管理。

    3.后台系统管理模块

    本模块主要由用户管理、转账记录管理、系统管理等3个部分组成。这是为了对注册用户的网上银行综合管理系统内容与个人信息进行管理,并对网上银行综合管理系统中的交易记录进行审核,审核通过后才能完成交易。综合所述,网上银行综合管理系统的总体功能需求如下图所示。

    3.课题研究的基本思路

    本文在对现在个人网上银行综合管理系统的普遍现状和工作特点进行调查分析之后,开始了“基于Pyhton的个人网上银行综合管理系统”的设计。本系统的设计分为以下几个主要阶段:

    (1)系统需求分析与功能设计。包括可行性分析、用户需求,收集各种关于系统功能设计的要求,确定系统的功能。

    (2)数据库设计。确定数据库结构,设计数据库的各种参数、创建数据库的表、关系图等数据库对象。

    (3)程序模块划分和实现。根据系统的使用对象划分不同的功能,对系统进行模块划分,分别编写代码,逐一实现系统的功能。

    (4)优化界面,对其进行修整和美化。

    更多相关内容
  • 银行排队叫号系统源码,若发现bug,欢迎指正,谢谢。操作系统是windows,开发工具vs2008
  • java实现银行管理系统

    千次阅读 2021-03-07 21:18:35
    本文实例为大家分享了java实现银行管理系统的具体代码,供大家参考,具体内容如下Bank类package First;import java.util.TreeSet;//银行类public class Bank {private String Bankname = "坑对对银行"; //银行名称...

    本文实例为大家分享了java实现银行管理系统的具体代码,供大家参考,具体内容如下

    Bank类

    package First;

    import java.util.TreeSet;

    //银行类

    public class Bank {

    private String Bankname = "坑对对银行"; //银行名称

    TreeSet holder = null; //银行存储的信息

    private static Bank INSTANCE = new Bank();

    private Bank() {} //私有化银行类

    public static Bank getInstance() {

    // TODO Auto-generated method stub

    return INSTANCE;

    }

    //存款功能

    public void saveMoney(User user,double money) {

    //初始金额与存入金额相加

    double sum = user.getSum()+money;

    user.setSum(sum);

    System.out.print(money+"存款成功!!!"+",当前余额是:"+user.getSum());

    System.out.print("\n");

    }

    //取款功能

    public void drawMoney(User user,double money,String pw) {

    if(user.getPw().equals(pw)) { //先判断取款密码

    if(user.getSum()>=money) { //判断余额

    user.setSum(user.getSum()-money);

    System.out.print("取款成功");

    System.out.print("\n");

    System.out.print("当前余额为:"+"\t"+user.getSum());

    System.out.print("\n");

    }else {

    System.out.print("抱歉余额不足!!! 当前余额:"+user.getSum());

    System.out.print("\n");

    }

    }

    }

    //查看余额以及信息

    public void looksum(User user) {

    System.out.print("姓名:"+user.getName()+",账号:"+user.getAccount()+",余额:"+user.getSum());

    System.out.print("\n");

    }

    //欢迎语句

    public void welcom(User user) {

    if(user.getSexual().equals("男")) {

    System.out.print(user.getName()+" 先生!!"+" "+(this.Bankname)+" 欢迎您!!!");

    System.out.print("\n");

    }else if(user.getSexual().equals("女")){

    System.out.print(user.getName()+" 女士!!"+" "+(this.Bankname)+" 欢迎您!!!");

    System.out.print("\n");

    }

    }

    //再见语句

    public void GoodBye(User user) {

    if(user.getSexual().equals("男")) {

    System.out.print(user.getName()+" 先生!!"+" "+(this.Bankname)+" 祝您生活愉快!!!");

    System.out.print("\n");

    }else if(user.getSexual().equals("女")){

    System.out.print(user.getName()+" 女士!!"+" "+(this.Bankname)+" 祝您生活愉快!!!");

    System.out.print("\n");

    }

    }

    }

    Data:数据存储类

    package First;

    import java.util.TreeSet;

    //模拟一个数据库

    //银行的数据库

    public class Data {

    TreeSet holder = new TreeSet(new MyComparator()); //用于存储用户信息的容器---自定义比较规则

    File file = File.getFile(); //获取一个文件类

    private static Data data = new Data();

    //单例模式--因为存储数据的类唯一.所以不能随意被实例化

    private Data() {} //私有化构造方法

    public static Data getData() { //提供返回该对象的静态方法

    return data;

    }

    //添加用户

    public void addUser(User user) {

    holder.add(user);

    System.out.print("注册成功!!");

    System.out.print("\n");

    }

    //删除用户

    public void removeUser(User user) {

    if(holder.contains(user)) { //如果容器中包含所user对象,则移除对象

    holder.remove(user);

    }else { //如果不包含则打印语句

    System.out.print("抱歉请检查输入的信息是否正确");

    System.out.print("\n");

    }

    }

    //获取容器

    public TreeSet getHolder() {

    return holder;

    }

    //写入容器

    public void setHolder(TreeSet holder) {

    this.holder = holder;

    }

    }

    FIie:文件IO类

    package First;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.ObjectInputStream;

    import java.io.ObjectOutputStream;

    import java.util.Iterator;

    import java.util.TreeSet;

    /*

    * 文件类--负责向内存中初始化信息以及程序结束后向内存中存入信息

    * */

    public class File {

    TreeSet holder = Data.getData().getHolder(); //从Data数据库中获取容器

    //文件类只供使用不能被任意实际化

    public static File FILE; //私有化一个File类

    private File() {};

    public static File getFile() { //对外界提供获取方法

    return FILE;

    }

    //保存到文件里

    public static void SaveToFile(TreeSet list) { //将获取到的容器存入到文件中----序列化

    ObjectOutputStream oo = null;

    try {

    oo = new ObjectOutputStream(new FileOutputStream(".\\src\\Test\\text1.txt")); //获取文件存储地址

    oo.writeObject(list); //将容器写入

    } catch (Exception ex) {

    ex.printStackTrace();

    }finally {

    try {

    oo.close(); //将流关闭

    }catch(IOException e) {

    e.printStackTrace();

    }

    }

    }

    //从文件里读取

    public static TreeSet ReadFromFile() {

    ObjectInputStream ois = null;

    TreeSet list = null;

    try {

    ois = new ObjectInputStream(new FileInputStream(".\\src\\Test\\text1.txt"));//反序列化从文件中获取容器加载到内存

    list = Data.getData().getHolder(); //获取容器

    list = (TreeSet) ois.readObject(); //从流中获取对象

    Iterator it = list.iterator(); //迭代器

    System.out.print("当前用户信息:");

    System.out.print("\n");

    System.out.print("\n");

    while(it.hasNext()) { //迭代初始信息

    User user = (User) it.next();

    System.out.print("\t"+"姓名:"+user.getName()+"\t"+"账号:"+user.getAccount()+"\t"+"密码:"+user.getPassword()+"\t"+"余额:"+user.getSum()+"\t");

    System.out.print("\n");

    System.out.print("\n");

    }

    } catch (Exception ex) {

    ex.printStackTrace();

    }finally {

    try {

    ois.close(); //将流关闭

    }catch(IOException e){

    e.printStackTrace();

    }

    }

    return list;

    }

    }

    MyComparator:自定义比较器类

    package First;

    import java.io.Serializable;

    import java.util.Comparator;

    //自定义比较器

    //想要存入集合必须实现序列化和反序列化

    public class MyComparator implements Comparator,Serializable{

    /**

    *

    */

    private static final long serialVersionUID = 1L;

    @Override

    public int compare(Object arg0, Object arg1) {

    User user1 = (User)arg0; //重写比较方法 --- 强转成User类型

    User user2 = (User)arg1;

    return user1.getAccount().compareTo(user2.getAccount());//比较两个银行账户

    }

    }

    Operate:系统核心

    package First;

    import java.util.Iterator;

    import java.util.Scanner;

    import java.util.TreeSet;

    //后台操作系统

    //后台管理员

    public class Operate {

    Scanner sc = new Scanner(System.in); //键盘录入

    TreeSet holder = Data.getData().getHolder(); //从Data数据库中获取容器

    Bank bank = Bank.getInstance(); //获取一个银行类

    File file = File.getFile(); //获取一个文件类

    //登录菜单

    public void registerMenu(){

    System.out.print("****************************");

    System.out.print("\n");

    System.out.print("\n");

    System.out.print(" 欢迎来到坑多多银行登录系统!!!\n");

    System.out.print("\n");

    System.out.print("****************************");

    System.out.print("\n");

    System.out.print("\n");

    holder = File.ReadFromFile(); //从文件中获取容器

    Data.getData().setHolder(holder); //把从文件中获取容器存储到数据库中

    int str=1; //从键盘获取数字

    while(str!=0) {

    System.out.print("****************************");

    System.out.print("\n");

    System.out.print(" 1: 登录 ");

    System.out.print("\n");

    System.out.print(" 2: 注册 ");

    System.out.print("\n");

    System.out.print(" 3: 忘记密码");

    System.out.print("\n");

    System.out.print(" 4: 注销用户");

    System.out.print("\n");

    System.out.print(" 0: 退出");

    System.out.print("\n");

    System.out.print("****************************");

    System.out.print("\n");

    System.out.print("请输入:");

    str = sc.nextInt();

    switch(str){ //根据用户输入的值进行选择

    case 1:

    System.out.print("请输入您的账号:");

    String account = sc.next(); //从键盘中获取录入用户名

    System.out.print("请输入您的密码:");

    String pw = sc.next(); //从键盘中录入密码

    User user = logon(holder,account,pw);

    if(user!=null) { //判断是否登录成功

    System.out.print("登录成功!!!!欢迎使用");

    System.out.print("\n");

    System.out.print("正在跳转到银行操作界面.........");

    System.out.print("\n");

    this.BankMenu(user); //如果登录成功则将user对象传入到银行操作界面并跳转

    }else {

    System.out.print("登录失败!!!请从新输入"); //如果登录失败打印此语句

    System.out.print("\n");

    }

    break;

    case 2:

    this.logon(); //调用注册方法

    break;

    case 3:

    this.modify(); //调用修改方法

    break;

    case 4:

    holder = logout(holder); //调用删除操作

    break;

    case 0:

    File.SaveToFile(holder); //退出系统式将信息保存到文件中

    System.out.print("再见!!!!");

    System.out.print("\n");

    default:

    System.out.print("输入错误!!!!");

    System.out.print("\n");

    }

    }

    }

    //登录方法

    public User logon(TreeSet holder,String account,String pw) {

    Iterator it = holder.iterator(); //获取迭代器

    while(it.hasNext()) {

    User user = it.next();

    if(user.getAccount().equals(account)&&user.getPassword().equals(pw)){

    System.out.print("登录成功!!");

    System.out.print("\n");

    return user;

    }

    }

    System.out.print("账户或密码错误 登录失败!!");

    System.out.print("\n");

    return null;

    }

    //注册方法体

    public void logon(){

    System.out.print("欢迎来到注册界面!!!!");

    System.out.print("\n");

    String name; //用户名

    String account; //银行账号

    String password; //密码

    String pw; //取款密码

    double sum; //账户金额

    String sexual; //性别

    User user = new User(); //先创建一个空参的user对象

    boolean flag = true; //语句的开关

    while(flag) { //将注册的信息依次输入

    switch(1) {

    case 1:

    System.out.print("请输入姓名:"); //依次从键盘中获取对应的姓名----正则表达式

    name = sc.next();

    user.setName(name); //将名字写入对象中

    case 2:

    System.out.print("请输入账号(9位数字):");

    account = sc.next(); //从键盘中获取账号

    String reges ="[0-9]{9}"; //正则表达式规则对账号进行限制

    if(!account.matches(reges)) { //如果不符合要求则报错

    System.out.print("账号不符合规范!!");

    System.out.print("\n");

    System.out.print("请重新注册");

    System.out.print("\n");

    break;

    }

    user.setAccount(account); //将账号写入对象中

    case 3:

    System.out.print("请输入密码(6位):");

    password = sc.next();

    reges ="[0-9]{6}"; //正则表达式规则

    if(!password.matches(reges)){ //如果密码不符合正则规则则报错

    System.out.print("密码不符合规范!!");

    System.out.print("\n");

    System.out.print("请重新注册");

    System.out.print("\n");

    break;

    }

    user.setPassword(password); //将密码写入对象中

    case 4:

    System.out.print("请输入取款密码(6位):");

    pw = sc.next();

    reges ="[0-9]{6}"; //正则表达式规则

    if(!pw.matches(reges)) {

    System.out.print("取款密码不符合规范!!");

    System.out.print("\n");

    System.out.print("请重新注册");

    System.out.print("\n");

    break;

    }

    user.setPw(pw); //将取款密码写入到对象中

    case 5:

    System.out.print("请输入金额:");

    sum = sc.nextDouble();

    user.setSum(sum); //将金额写入到对象中

    case 6:

    System.out.print("请输入性别:");

    sexual = sc.next();

    user.setSexual(sexual); //将性别写入到对象中

    case 7:

    if(!holder.contains(user)){

    Data.getData().addUser(user); //一切准确无误后将user存入数据库Data中

    }

    else {

    System.out.print("用户存在!!!");

    System.out.print("\n");

    //结束循环

    }

    flag = false;

    break;

    }

    }

    }

    //忘记密码操作

    public void modify() {

    boolean flag = true;

    Iterator it = holder.iterator(); //获取迭代器

    System.out.print("请输入账户:");

    String account = sc.next(); //从键盘中获取账户

    while(it.hasNext()) {

    User user = it.next();

    if(user.getAccount().equals(account)){ //如果容器中有这个对象则对它进行修改

    System.out.print("请输入新账户的密码:");

    String pw = sc.next(); //从监盘上录入新的密码

    String reges ="[0-9]{6}"; //正则表达式规则

    if(!pw.matches(reges)) { //如果密码不符合正则规则则报错

    System.out.print("密码不符合规范!!");

    System.out.print("\n");

    }else { //正则表达式判断是否符合条件

    holder.remove(user); //先从原容器中删除user

    user.setPassword(pw); //修改user的属性

    holder.add(user); //然后再向容器中添加

    System.out.print("修改成功!!!");

    System.out.print("\n");

    flag = false;

    break;

    }

    }

    }

    if(flag) {

    System.out.print("没有找到该用户");

    System.out.print("\n");

    }

    }

    //注销方法

    public TreeSet logout(TreeSet list) {

    String username; //用户名

    String password; //密码

    System.out.print("请输入用户账号:");

    username = sc.next(); //从键盘录入用户名

    System.out.print("请输入密码:");

    password = sc.next(); //从键盘录入密码

    Iterator it = list.iterator(); //获取迭代器

    while(it.hasNext()) {

    User user = (User)it.next(); //获取对象

    if(user.getAccount().equals(username)&&user.getPassword().equals(password)){

    list.remove(user); //如果录入的信息匹配则从容器中删除user对象

    System.out.print("注销成功!!");

    System.out.print("\n");

    return list;

    }

    }

    System.out.print("账号或者密码错误"); //不匹配打印提示语句

    System.out.print("\n");

    return list;

    }

    //银行操作界面

    public void BankMenu(User user) {

    bank.welcom(user); //银行调用欢迎语句

    System.out.print("****************************");

    System.out.print("\n");

    System.out.print("\n");

    System.out.print(" 欢迎来到坑多多银行擦操作系统!!!\n");

    System.out.print("\n");

    int str = 1;

    while(str!=0) {

    System.out.print("****************************");

    System.out.print("\n");

    System.out.print(" 1: 取钱 ");

    System.out.print("\n");

    System.out.print(" 2: 存钱 ");

    System.out.print("\n");

    System.out.print(" 3: 查看余额");

    System.out.print("\n");

    System.out.print(" 0: 退出登录");

    System.out.print("\n");

    System.out.print("****************************");

    System.out.print("\n");

    System.out.print("\n");

    System.out.print("请输入您的选项:"); //从键盘中读取字符串

    str = sc.nextInt();

    switch(str){ //根据用户输入的值进行选择

    case 1: //取钱选项

    System.out.print("请输入取款密码:");

    String pw = sc.next(); //从键盘获取输入的密码

    if(user.getPw().equals(pw)) { //将输入的取款密码与用户的密码进行比对:如果相同则继续执行

    System.out.print("请输入取款金额:");

    double money = sc.nextDouble(); //从键盘获取输入的金额

    if(money>=0) { //判断金额是否有误

    bank.drawMoney(user, money, pw); //调用取款方法

    }else {

    System.out.print("输入金额错误!!!");

    System.out.print("\n");

    }

    }else {

    System.out.print("输入密码有误!!!");

    System.out.print("\n");

    }

    break;

    case 2:

    System.out.print("请输入取款金额:");

    System.out.print("\n");

    double money1 = sc.nextDouble(); //从键盘获取输入的金额

    if(money1>=0) { //判断金额是否有误

    bank.saveMoney(user, money1);; //调用存款方法

    }else {

    System.out.print("输入金额错误!!!");

    System.out.print("\n");

    }

    break;

    case 3:

    bank.looksum(user); //调用银行---查询账户操作

    break;

    case 0:

    bank.GoodBye(user); //调用结束语句

    break;

    default:

    System.out.print("输入错误");

    System.out.print("\n");

    }

    }

    }

    }

    User类:

    package First;

    import java.io.Serializable;

    /*

    * 这是一个User类

    * */

    public class User implements Serializable{

    /**

    * 实现接口,用于序列化和反序列化

    */

    private static final long serialVersionUID = 1L;

    private String name; //用户名

    private String account; //银行账号

    private String password; //密码

    private String pw; //取款密码

    private double sum; //账户金额

    private String sexual; //性别

    //获取用户名

    public String getName() {

    return name;

    }

    //写入用户名

    public void setName(String name) {

    this.name = name;

    }

    //获取账号

    public String getAccount() {

    return account;

    }

    //写入账号

    public void setAccount(String account) {

    this.account = account;

    }

    //获取密码

    public String getPassword() {

    return password;

    }

    //修改密码

    public void setPassword(String password) {

    this.password = password;

    }

    //查看余额

    public double getSum() {

    return sum;

    }

    //修改余额

    public void setSum(double sum) {

    this.sum = sum;

    }

    //写入性别

    public String getSexual() {

    return sexual;

    }

    //修改性别

    public void setSexual(String sexual) {

    this.sexual = sexual;

    }

    //获取取款密码

    public String getPw() {

    return pw;

    }

    //写入取款密码

    public void setPw(String pw) {

    this.pw = pw;

    }

    //hashCode比较方法

    @Override

    public int hashCode() {

    final int prime = 31;

    int result = 1;

    result = prime * result + ((account == null) ? 0 : account.hashCode());

    result = prime * result + ((name == null) ? 0 : name.hashCode());

    result = prime * result + ((password == null) ? 0 : password.hashCode());

    result = prime * result + ((pw == null) ? 0 : pw.hashCode());

    result = prime * result + ((sexual == null) ? 0 : sexual.hashCode());

    long temp;

    temp = Double.doubleToLongBits(sum);

    result = prime * result + (int) (temp ^ (temp >>> 32));

    return result;

    }

    //equals比较方法

    /*

    * 知识点:

    * public boolean equals(Object obj)名称不可改变

    * */

    @Override

    public boolean equals(Object obj) {

    if (this == obj)

    return true;

    if (obj == null)

    return false;

    if (getClass() != obj.getClass())

    return false;

    User other = (User) obj;

    if (account == null) {

    if (other.account != null)

    return false;

    } else if (!account.equals(other.account))

    return false;

    if (name == null) {

    if (other.name != null)

    return false;

    } else if (!name.equals(other.name))

    return false;

    if (password == null) {

    if (other.password != null)

    return false;

    } else if (!password.equals(other.password))

    return false;

    if (pw == null) {

    if (other.pw != null)

    return false;

    } else if (!pw.equals(other.pw))

    return false;

    if (sexual == null) {

    if (other.sexual != null)

    return false;

    } else if (!sexual.equals(other.sexual))

    return false;

    if (Double.doubleToLongBits(sum) != Double.doubleToLongBits(other.sum))

    return false;

    return true;

    }

    //初始化用户

    User(String name,String account,String password,String pw,double sum,String sexual){

    this.name = name;

    this.account = account;

    this.password = password;

    this.sum = sum;

    this.sexual = sexual;

    this.pw = pw;

    }

    //空参构造函数

    User(){

    }

    }

    Main()类

    package First;

    public class Test {

    //测试类----唯一的主函数

    public static void main(String[] args) {

    Operate operate = new Operate();

    operate.registerMenu(); //调用登录方法

    }

    }

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

    时间: 2019-12-23

    展开全文
  • 银行核心系统是什么?

    千次阅读 2021-07-22 17:35:24
    银行核心系统是什么? 2011-01-03 csdn银行核心系统是什么 银行核心系统的英文原意CORE Banking, CORE其实不是“核心”的意思这么简单,它的全称是: Centralized Online Real-time Exchange (集中式在线实时交互...

    银行核心系统是什么?

    2011-01-03 csdn 银行核心系统是什么

    银行核心系统的英文原意CORE Banking, CORE其实不是“核心”的意思这么简单,它的全称是: Centralized Online Real-time Exchange (集中式在线实时交互)。注意两个重要的关键词“集中”和“实时”。

    • 什么是“集中”,也就是说外围系统或者说辅助系统,不管是柜面系统也罢,ATM也罢,网银也 罢,它们的业务流程最终都要汇集到这个核心系统。就像一台计算机的所有的操作最终都要归结到CPU的指令。
    • 那什么是“实时”,就是那些系统需要即刻做出反 应的操作。你在ATM机上取款,你取了多少钱,银行系统内你的帐户余额马上就要扣掉多少钱。这必须要实时的,即使你拿北京开的银行卡在深圳的ATM机上取款,系统也必须要实时反应,否则银行的麻烦就大了。同样,你存款,你在柜面上把钱存进去,你账面的数据变化也要马上反应搞系统中,否则你的麻烦就大了。

    那我们在看看这个“核心”系统需要包含什么样的核心功能?

    其实上面的例子也指出来了:资金流相关的帐务功能

    怎么体现“集中”呢?

    首先和银行打交道的事情,银行的三大类主要业务(资产、负债、中间业务),基本就是钱的事情。绝大多数业务流程(不敢武断地说“全部”)都涉及到资金流。也就说这些业务流程最终都集中到某种形式的帐务(资金)操作。

    那“实时”呢?

    更好理解了。这些帐务处理都必须要实时。你说你把这个月工资拿到柜面存了,查帐却发现账面数字没变,你要不要骂娘。你家那口子要不要怀疑你又藏私房钱了。

    一个最基本的核心系统(后面还会讲到更复杂的)到底应该包含什么功能?

    很简单:需要实时处理的帐务功能

    譬如,汇款的功能。注意这里指的是一个 集中式的汇款功能。不管手机、网银、还是柜台,都只是不同的渠道集中调用一个核心的汇款功能而已。这些渠道统统剥离到外围系统里面,核心系统留下的只 是一个知道从哪个帐户转多少钱到哪个帐户,然后扣除银行手续费的核心汇款功能(当然真实系统的转账功能要复杂得多,这里只是介绍原理)。同样,其它各类银行业务也可以抽取出类似的核心功能,剥离出外围功能。

    辅助功能都剥离到外围系统去了,留下一个小而精的核心系统处理核心业务,这就是“瘦核心,大外围”。

    这样做的好处在哪里?

    • 首先结构清晰功能明确啦。每个业务流程都一个开始于外围,集中到核心系统,核心系统再反馈结果到外围。大伙该干嘛干嘛,责任明确。企业管理不都提倡这个嘛。
    • 其次,这样的系统架构可以快速适应需求变化。市场和客户的需求永远不会恒定的,唯一恒定的东西就是“需求一定会变”。就以支付为例。现在的电话支付,手机支付,网上支付手段多多。谁知 道以后会有多少新的支付手段。没准以后超市里搞个指纹仪什么的,按个指纹那边银行帐户直接就扣款了。要不让你打个喷嚏,那边仪器分析你的唾沫提取DNA,然后定位你的账户什么的。如果每个新的支付手段都要开发一个全 新的系统,那银行IT部门要累死掉了。怎么办,利用核心系统呀。再奇特的支付功能,始终只是渠道的不同,最终的操作只是核心系统里面的一个转账操作就行 了。增加一个新的支付方式,对于银行系统来说,只是增加一个外围功能去和核心系统交互而已,成本远远小于搞出一个完整的系统。

    二,国内银行核心系统建设情况调研报告

    csdn 国内银行核心系统建设情况调研报告
    简书 国内银行核心系统建设情况调研报告
    百度文库 各银行核心业务系统分析

    各银行核心业务系统分析

    三,银行核心系统入门简介

    文章来源与某位大神的力作,写的非常好,科目的地方首位科目号有待商榷,但总之看完后很多东西一目了然。

    2013-02-06 银行核心系统概念入门简介
    2012-03-20 百度文库 银行核心系统入门简介(关于业务)
    2014-10-09 银行核心系统入门简介(系列一)
    csdn 银行核心系统软件开发 科目常识
    作者疑似招行的核心技术人员。

    本文的目标读者是准备从事银行核心系统开发、维护的从业人员。请注意,是“准备”,换句话说,可以理解为一份对科技人员,尤其是对新入门的科技人员业务知识方面的培训手册,旨在让诸位从业务方面迅速上手(从技术角度上手的手册我已经贴过一份了,所以如果是用400的同行,可以结合本手册双剑合璧,效力倍增)。这里的着重点将会主要在于简单的银行会计原理,以及银行整体的业务流程,还有相应的模块实现手法和注意事项,对金融的会计知识方面应该可能会比较粗浅,这一点与金融系统常见的业务培训手册有所不同,注意体会。

    基于此,本文将会假设读者具备一定的计算机技术,具备少量银行方面的业务知识,所以如果有从事非IT部门的读者(比如财务信贷的同事们),就请不要太计较里面的表述。当然如果有错误,还是非常欢迎指出的。

    对于已具备了若干开发、维护知识,或者是即将采用国外系统来建设的同行们而言,本文的内容可能就过于浅显了,看得不爽不要怪我没有事先提醒。

    考虑到某方面的问题,这里的系统简介将尽可能的脱离某个具体的系统,仅就银行业务核心系统的共性,进行介绍以及探讨。

    最后再说一下,没有什么手册、心得是万能的,个人的LEVEL UP始终是要靠自己的领悟,这里只是希望能让诸位新人不用象很多人当年一样,独自摸索与徘徊。

    1 科目

    科目常识基本法则之一:

    资产 =负债 +所有者权益。(新会计准则有所不同)

    比如说,我们手头上有40万,买了一个100万的房子,找银行贷款了60万,那么资产就是100万,负债是60万,所有者权益是40万。可以简单的把所有者权益就理解成为是真正属于自己的钱。

    再引申一下,早些年乃至现在,香港人所谓的“负资产”的说法是非常错误的,因为“负资产”实际上是指房子的市值比向银行贷的钱还要小,也就是负债大于资产,所以严格的来说,应该称之为“负所有者权益”才对

    资产,从理论上来说,是不可能为负的,最多也就是零。一个号称是金融中心的地方,实在是不应该出现这种失误,不过算了,不要和他们计较。

    就银行业务而言,会使用会计科目号来对账务进行标识,会计科目号最长为5位,国家标准,通常分为下面六种,这里只做简单介绍,详细科目可结合著名的的“业务状况表”来进行理解。

    再次重申,下面的说法绝对不严谨,仅仅只是为了便于IT人员理解银行的会计原理、业务知识。

    1.1 资产

    资产类的科目,用“1” 作为首位科目号,如“1011”,表示现金。

    所谓资产,也就是说“理论上属于银行的钱”,比如说现金,贷款等**。

    比如说某家分行,有100万现金,然后把这100万都贷出去了,那么资产仍是100万,只不过归属(科目)由现金变成了贷款。至于这笔贷款能不能收回,这个不归我们管,就算不能回收,只要没被核销(核销,术语之一,可以理解为银行不要这笔贷款了),那么就仍然属于资产,所以我们称之为“理论上属于银行的钱”。

    资产类科目都是借方科目,也就是借记时余额增加,贷记时余额减少。

    1.2 负债

    负债类的科目,用“2”作为首位科目号,如“2011”,表示对公存款。

    本来不属于银行的钱,就称之为“负债”

    比如说我们存在银行的钱,虽然银行可以使用这笔钱,比如说把它贷款贷出去啊,比如说打新股啊,买QDII啊,但是这笔钱只要我们去取,原则上银行就应该给我们,也即是大家常常在营业大厅里看到的“存款自愿,取款自由”之类的意思。这类钱,可以简单的理解为“本来不属于银行的钱”,也就银行欠我们的钱。

    负债,很有趣的东西喔,银行是负债经营的,比如说一家银行贷款有100亿,其实它本身是没有那么多钱的,这些钱都是来自于我们存在它那的钱。如果大家一起都去银行的钱取出来,那它就经营不下去了,这种恶劣的行为,称之为“挤提”,是很不友善的,是要负责任的,我们不要去做。

    负债类科目都是贷方科目,也就是借记时余额减少,贷记时余额增加。

    1.3 所有者权益

    所有者权益类的科目,用“3”作为首位科目号,如“3121”,表示利润分配。

    上面说过了,所有者权益,也就是真正属于银行的钱,即是所谓的“核心资本”。原则上,它包括了一家银行注册时的资金,历年来的盈利(假设有盈利的话,当然还要扣除各类成本开销),如果是股份制银行的话,还包括股本金之类的吧。

    这类科目相对数量较小,金额较大。

    所有者权益类科目,增加记贷方,减少记借方,余额反映在贷方。

    1.4 资产负债共同类(往来类)(共同类)

    资产负债共同类,通常表示往来账户,用“4”作为首位科目号,如“46411”,表示通存通兑。

    这类科目,通常是指一些往来类账户,所谓往来类账户,嗯,就是金融往来的账户喽。

    这个科目有点麻烦,可能要结合具体业务来解释一下:

    比如说我们在招行有个账户,然后跑到工行的ATM上去取钱(招行也是,中山这种伟人的故乡居然都不开个点,严重BS一下),那么取款成功之后,我们的招行上的账户的钱就少了,工行ATM里面的现金也少了。这笔钱是工行替招行先支付的,要找招行要的。所以工行一定会有一个科目,用来标记它有多少钱要找招行要;而招行也要有一个科目,也是要用来标记它有多少钱要给工行。(怎么要,那在后面清算一节里面会提到。至于跨行ATM的取款原理,就不用再细说了吧。)这个用来标记应付,应收的科目,就是往来类科目,对于工行方而言,当时使用到的就是一个类似于资产类的科目(有点类似于应收账款的意思,或者也可以理解成一种短期的贷款,总之就是工行先付出的资金);招行当时使用的就是类似于负债类的科目。

    上面提到的,因为是银行与银行之间的业务往来,所以用来标识资产与负债的科目会有分别,如果是行内之间的往来,那么不会搞得那么复杂(或者也可以说搞得更复杂),就会用一个科目来搞定,这个科目根据具体需要,临时用的,有时表示资产,有时表示负债(其实也就是科目上的余额有时是借方,有时是贷方。因为这个科目既不是资产,也不是负债,只是临时用来表示营业往来的,通常每天会清零,也就是所谓的清算。

    一般而言,城市级别的商业银行因为是一级法人,所以清算之后,行内往来账户上余额为不为零都没什么关系,反正都是自已家的钱;而信用社会比较麻烦一点,因为通常一个联社都是由多个信用社组成,每个信用社都是一个法人,所以联社内部的往来类账户原则上每天应该都清零,否则账务上就不好看了。(注意,这里指的只是行内的往来账,如果是银行与银行间的,那每天一定是要清零的,否则就是属于错误的情况了)

    这类科目在我们做过的项目里,基本上都简化了,只有一个轧差类型的。也就是把当天的借方发生额和贷方发生额一减,哪个大就谁记在哪边。

    我记得以前还有一种双方类的科目,那真是玩死人。双方类的科目是指这个科目既有贷方余额,又有借方余额;对应贷方余额,既有借方发生额,又有贷方发生额,同理,对应借方余额,也是既有借方发生,又有贷方发生,如果只有上期的借贷方余额,以及当期的借贷方发生额,那是无论如何也推算不出当期的借贷方余额各是多少的。(必须根据发生账务时,是借方余额,还是贷方余额来判断),不知道这类科目的起因为何,总之如果有的而且可能的话,最好能拆分之几个性质单纯一点的子目来处理。

    不好意思,因为对这类科目感触颇深,也被玩过很多次,被玩很久,一时激动,就多说了几句。

    1.5 损益类

    损益类的科目,用“5”作为首位科目号,如“5011”,表示利息收入。

    损益类科目,理解起来应该不难,就是指银行在一年的业务里面的收支科目。比如的存款利息,对于银行来说是一笔支出;贷款利息,对于银行来说,是一笔收入。这两个科目就都属于损益类科目。

    一般来说:

    收入类科目属贷方科目,借记时增加,贷记时减少;
    支付类科目属借方科目,贷记时增加,借记时减少。

    在理解上,可能与资产、负债类的科目有些相反:

    资产是指属于银行自己的钱,是借方科目;对应于这里,收到的钱是银行自己的,却又是贷方科目。

    这里,按会计原理来理解可能会更简单一点,下面一章会讲到。

    1.6 或有资产负债类

    或有资产负债类的科目,用“6”作为首位科目号,如“6011”,表示承兑汇票。

    闻歌知雅意,顾名思义,“或有”,那自然就是“或者有”,也就是可能没有了,所以如果没见过也不奇怪。

    这类科目见得少,一般可以忽视它的存在。

    1.7 表外科目

    用“7”作为首位科目号。

    1.8 其它

    这里再罗嗦一下,在科目下面呢,一般为了便于分类统计,所有的银行都会再设子目(一个子目一般又会对应多个小子目,或者说是说是多个账户),这个子目,有的地方叫“业务代号”,有的地方叫“结算码”,总之都是一个意思

    要注意一下,科目号是国标,子目通常是自己内定的

    对应于信用联社,就有可能是省里统一定的。也就是说科目这个东西走遍全国大致上都是一样,子目这个东西可能出省,出了城市,或者说一个市里不同的银行,可能都不一样。

    2 简单会计原理

    2.1 内部账户

    这个问题,我在刚学的时候,曾经颇疑惑了一段时间,所以虽然很简单,但还是单独拿出来说一下。

    所谓内部账户,是与客户账户相对应的

    也就是说这些账户不是用来登记、反应客户的账户信息,而是反应行内的账务情况,比如说损益类科目的账户,就都是内部账户

    • 客户的账户,一般是客户来银行开户的时候,才建立的用来登记账务的账户;
    • 内部账户,一般是分行成立之初,统一生成的。(一般都一个专门的程序,由操作人员来调用的吧)

    其实对于内部账,在会计原则上,登记个科目发生可以。至于增加子目,乃至内部账户的概念,主要是为了后续的分类统计以及相应的分析。

    说到这个账户,就顺便想起了表内表外的问题。

    • 表内账,都是正正式式,真金白银的钱;比如我们的存款什么之类的。-

    • 而表外账,通常是一些统计之类的东西,比如说现在分行里有多少本存折啦,还有已经核销的贷款之类的。

    • 表内账的单位,都是“元”;

    • 表外账的单位,就百花齐放了,有的是“元”(比如说已核销贷款),有的是“本”或者是“张”,比如说存折或者说什么有价单证。而最后,表外账在汇总统计的时候,不管是什么单位,就是统统一加了事,对于不是财会专业的,尤其是我们搞计算机的人来说,这种加法简直有些不可理喻,总之银行会计上就是这样处理。

    所以说,一般报表里面,大家会对表内账比较关注,对表外账的要求不是太严格(我是这样偷偷的说,各位怎么处理是大家自己的事)。

    2.2 复式记账法

    只要是与会计有关的书,就一定会提到复式记账法,也称为借贷记账法,这里就不多解释,简单说一下。

    有借必有贷,借贷必相等”,这两句经典的话,是针对表内账的。

    对于表外账,用的其实是单式记账法,有的叫“收”、“付”,也的也还是用“借”,“贷”,要结合具体的业务来理解,这里就不展开了。如果没有特别说明,下面的描述都是针对表内账的。

    对于银行业务来说,最简单的是一借一贷,此外,还有一借多贷,一贷多借。多借多贷在银行业务里中不允许的,因为这样无法精确的体现账务的起始与流向。不过在企业会计中,多借多贷又是允许的,所以说凡事无绝对。

    有些时候,基于某些特殊的的原因(常见的主要是频繁的锁表问题),可能会临时采用单边记账,但是最后一定会汇总补齐,否则就会出现“借贷不平”这样的严重问题

    2.3 冲账

    做错了账,要改正它,就可以理解为冲账。

    冲账有两种,一种是蓝字冲账,一种是红字冲账。

    • 所谓的蓝字冲账,是指与原账务方向相反,金额为正的一种记账方式。
    • 红字冲账,就是指与原账务方向相同,金额为负的一种记账方式。

    蓝字冲账,本质上是做一笔新的业务,仅仅只是实现了最终的余额正确,发生额会虚增,所以一般的明显有错的账务,会要求使用红字冲正

    红字冲账因为是负数发生,所以在统计的时候,发生额将会与原来的交易抵销,这样的话发生额就很严谨了。

    实际上,对于一个系统而言,通常一笔业务的发生,并不仅仅只包括账务的登记,还会更改许多表中的数据。比如说一笔简单的取款交易,除了登记账务之外,客户的账户上的余额还会减少,这个很好理解吧。那么在冲账的时候,还需要将客户上的钱给它加回去。所以,关于冲账业务的设计,其实也是一个比较有趣的话题,这一点,将会在后面的章节中进行探讨。

    3 业务流程描述

    对于一个没有在柜面实习过的人,描述一下银行的业务流程,可能是有助于理解系统架构的。

    银行的业务,大致上可以分为财务类的业务,以及非财务类的业务

    非财务类的业务这里不做讨论。

    财务类的业务,又可分为自动业务,以及非自动业务。

    • 非自动业务,就是那些必须在柜台办理的业务,比如说一些转账业务,或者金额较大的存取款业务之类的。这类业务,因为是由柜员发起的,所以会有一些单据打印留底,以做传票使用。
    • 而自动类业务,就是由系统自动处理的,比如说我们在A分行有个账户,然后非要跑到B分行去取钱,那么B分行那部分的账务,对于B分行而言就是非自动业务;而A分行那部分的账务,对于A分行而言就是自动业务。

    自动业务因为是自动发生,所以需要业务人员打印报表的时候,才能知道发生了什么业务。

    柜员日间做各种各样的业务,然后到了下午关门以后,打印一份“科目日结单”,然后用柜员手头留存的传票,按科目逐一汇总累计,与打印出的科目日结单上的金额进行比对。有错一定要一查到底。所以原则上,这时打印的科目日结单,应该不包括自动业务,否则就会对应不上。

    业务系统在批处理的时候,还会进行一些自动的账务处理,然后最后系统还应该会再打印一份完整的科目日结单,以及日计表(可以理解为业务状况表的简洁版)。至于那些自动业务,系统在批处理的时候,或者是柜员主动查也行,总之就是会有一份“他代本”的传票(对应于上面提到的业务,A分行的自动业务就应该属于A分行的“他代本”传票。而B分行的传票因为是非自动业务,所以在交易当时就会有相应传票产生并打印了)

    到了第二天,分行开门后开始营业前,业务人员需要下载打印各类报表,不过主要的就是前面说的那两份,然后再看看,如果借贷发生、余额都相等,所有的非自动业务都有传票,而且和整个科目日结单都可以对应上,那么就表示昨天的账务完整无误,然后大家就可以欢天喜地的开始新一天的业务了。

    4 常见规范及检测

    4.1 传票以及日志

    从最基本的说起,通常来说,所有的账务程序都需要打印传票,传票格式通常都是统一的,找份以前看看就可以了。

    对应于转账业务,需要打印转账借、贷方双方的传票。

    而对于现金业务,则只打印一张传票就可以了,借贷方向采用非现金科目的方向。(我个人认为,可能是因为标识了现金传票,所以对方科目就自然是现金,于是就不需要再打印了,猜的)

    所以我们在开发程序的时候,打印传票这一步,一般不会特别强调,都是默认要做的。如果不太清楚的时候,一定要主动向需求设计人员询向,千万不要嫌麻烦,抱有侥幸心理。这种东西如果测试的时候漏掉了,是一定会有人要求补上的。(我在N多项目里都见过漏写传票,然后在程序上线前夕被人要求赶紧加班补制的,所以千万不要嫌麻烦)

    在日终批处理的时候,可能有些数量庞大的业务,比如说代收/付,结息什么之类的,动不动就是几十万笔,一张张生成、打印太不经济,通常会考虑采用打印一张汇总传票,然后加上一份明细清单的方式。还有的时候,如果上百万的话,可能明细清单都省掉,想办法导成电子数据都是有可能的。

    上面说的是账务相关的业务。而非账务类的业务,如果涉及到修改类的业务的话,比如说修改密码,修改客户名之类的,通常需要登记日志(LOG),用来记录,以便查询。

    有的时候,为了统计业务量,或者是为了分析排障,还有可能要求对每一笔发送到主机的业务数据都登记下来,这时候最好采用一种统一的方式来进行登记,以及数据的定期清除,因为这类数据量应该比较大。

    4.2 常见检测内容

    发生一笔业务的时候,是一定需要进行若干检查的。比如最起码,我们去取钱的时候,就一定会检查密码。这里对一些经常见到的,较为普遍的检查简单介绍如下,套用一句合同上流行的话,叫做 -- 包括但不仅限于以下条款:

    1、账号/卡号是否存在,是否可以正常使用
    2、账号与客户所提供的凭证(通常这是指存折客户,对于卡用户而言,账号就是卡号,或者是可以根据卡号查询出相应的账号)是否匹配。
    3、密码、证件号码(如果需要检查的话)是否与主机数据一致(印鉴什么的需要业务人员肉眼核对。现在又出了一种加密机,如果采用了这种先进技术,那当然还需要检查这种加密后的信息是否一致了)
    4、在转账的时候,一定要检查转出转入方的户名与账号/卡号中的户名是否一致。(对私客户还好办一点,如果是对公客户的话,名字又长,括号什么的再一加,经常会出现问题,总之是一定要检查)
    5、如果是取款类业务(比如转账业务的转出方也算),一定要检查账户的可用余额是否足够。
    6、大家一起来。

    5 系统架构及部分模块常见设计方案

    5.1 常见总体架构

    这里如果用图可能效果会更好,不过我不会用VISIO,所以就算了。

    一般硬件架构,都是一个主机,一个前置机(大前置),前置机就对外了,比如业务人员用来作业务的终端啦,ATM,网银,电话银行什么之类的可能就都对应这个大前置了。大前置,或者是中间业务平台,也是一个很值得探讨的问题,可以做得很大,比如建行的大前置,又比如X天的中间业务平台其实也不错,这里不做深究。

    就软件架构而言,核心系统一般可以分为业务模块,账务模块,和总账模块

    • 总账模块通常记录了一些账务的汇总信息,比如说科目总账的日、月、年的发生、余额。银行中大部分的报表都需要通过取总账模块中的数据来生成。总账模块的数据一般是取自账务模块中,当天的账务数据。(当然,也有很多报表,需要整合业务模块与总账模块两部分的数据一起来出)
    • 账务模块,就是用来登记账务的,这部分一般会做得比较通用化,方便各个业务模块来调用。
    • 业务模块,当然就是实现各个业务的子模块了,通常模块之间相对独立又互有关联,如果是账务类业务,当然就要调用账务模块中的程序。如果是非账务类的业务,那可能业务模块内部处理一下就可以了吧。

    一般业务模块的数据会对实时性要求较高,而总账模块没有什么实时性的要求,不过总账模块重在统计分析,所以数据量一般会比较大。

    5.2 计息

    有的系统可能没有把计息单独列为一个模块,而是直接嵌套在各个业务模块之间了,不过设计成一个模块,个人认为可能会显得比较专业一点,至于到底好不好用那就见仁见智了。

    刚接触银行业务的时候,曾经很执着,很傻很天真的想过活期账户到底是怎样计息的,因为定期账户的计息方式相对简单,余额乘天数就对了,但是活期账户的余额是常常在发生变动的,所以前20多年我一直都不知道银行每年给我算的活期利息到底对不对。

    银行会计上,通常都会通过“积数”这个东西来计息。

    何谓积数?就是余额*天数,所以积数的单位应该是“元天”

    比如说

    利息 =(账户余额*天数*利率)/ 360

    在这个公式里,账户余额*天数就等于积数,于是这条公式也可以写为

    利息 =(积数*利息) / 360。

    定期账户因为账户余额通常不发生变化,所以一般不会涉及到积数。
    活期账户采用动户累计积数的方式来计息。也就是说账户余额没有发生变动,就什么事都不干;当账户余额需要发生了变动时(比如说取款),那么业务模块里就将上次账户变动日,到当前日期的天数计算一算,然后用变动之前的账户余额乘以这个天数,然后把这个积数累加到之前的积数上。最后计息的时候,就使用这个积数乘以利率再除360。
    在设计的时候,就需要把每次账户变动的日期都登记下来,还需要有地方记录账户的当前积数。

    对公计息,或者是一些需要计息内部账,有可能是每天计积数,也就是每天把账户余额累加到积数中。之所以这样设计,是因为对公以及内部账户的数量远小于对私账户,每天把每个账户都过一遍,花不了太多时间;而要是每天把储蓄账户都过一遍,就有点类似于结息了。

    (对私账户多的银行,有可能达到上千万户,尤其是些代理了社保,医保的银行,不可小看)不过现在有些很好很强大的国外系统,对于利息的处理,是每日计提,当然,这样设计也应该会有它的独到之处。

    刚才这里提到的了需要计息的内部账,那么一般而言,什么样的内部账需要计息呢,我想,应该是不同法人之间上存下放的款项需要计息。对应于一般的商业银行以及统一了法人的信用联社,因为全市是一级法人,可能就没有需要计息的内部账了。而对于没有统一法人的联社,因为每个信用社都是一个独立的法人,那么信用社存放在联社的用来做往来清算用的资金,就是需要计算利息的。还有的银行,对于贷款的处理,也会有资金池的概念,这时总行下拨分行的用于贷款钱,也是要计息的。

    这里可以看到,对于计息模块而言,积数是一个很好用的东西。积数除了计息,还有很多其它的用途。比如说招行的金卡,说的是“日均存款5万元以上不收取账户管理费”,那么,这个日均存款5万是如何判断呢,我很久以前曾经问过一个大堂里的MM(跟我同姓喔,惜乎已经有BF了),她说是根据积数来判断的,也就是每个月需要增加150万的积数,这样听起来就很合理了吧。

    对于某些业务来说,可能需要登记利息的明细。比如说贷款的复利的计算,就是根据利息来的。无论是正常贷款,还是逾期贷款,都会生成利息。生成的利息如果未及时归还,则会再根据这笔利息生成相应的复利。复利的复利,喔,太可怕了,也还是视为复利吧。

    总之,我的意思就是说,储蓄、对公账户这样的结息,在计息模块中可以不用登记利息的明细,因为最后结息的时候根据积数一次搞定;而对于贷款(或者是其它有需要的模块),可能需要在每一笔利息产生之后,都把它登记下来,已保留行使进一步措施的权利。

    除了贷款之外,还有一些定期账户,也最好采用明细的方式进行处理,越细越好,比如什么零存整取,教育储蓄之类的,要是没有详细的每期存款登记,漏存登记等等,是很容易就被它玩死的。

    通知存款以前觉得它很可怕,现在想想,突然又觉得没那么可怕,无非就是通知取款,通知期限内的积数登记,然后取款又或者取消通知。可能最主要的,就在于通知期限内的积数计算。总之提取一个计息模块,为这类业务特别定制一些明细文件是很好的一个选择。

    提到计息,也就顺便说一下利息税。国家在这十年来,调整了两次利息税税率,一次是涨成两分,一次是降成五厘,就那么一点钱,调来调去累不累,要收就收,不收拉倒,还搞什么分段计税,烦死个人。在这里,不知道有没有人是负责搞利息税这部分程序的,也不知道去年改这部分程序的时候,有没有很不爽过。其实要是早考虑到这种情况,倒是可以一开始就通过设置利息税参数表,然后修改计息程序,读取利息税参数表,最后根据不同阶段的参数,分段计息算税。这个方法倒是可行的,也实现过,对于整存整取的定期来说,算得上是一劳永逸,不过对于活期而言,每次调整利息税税率的时候可能就要搞一次类似于结息的东西了,好象没有一劳永逸的方法。

    在国外的先进系统中,还有一种精采的倒起息可以让人一筹莫展。这种玩法的意思,就是说当客户来柜台前做个什么交易的时候,允许账户的起息日期在业务发生日之前。比如说有人7月14号来到柜台前还一笔贷款的款,然后说我这笔钱明明7月7号就到账上了啊,为什么银行不给我扣,非得让我贷款逾期之类的话。然后核查,如果属实,那就倒起息一把,现在虽然是7月14号,但还是当它是7月7号还的。(好象是这样,也可能是我说错了,大家对这段解释千万不要太放在心上)总之,如果有倒起息的需求,那必须在最开始设计的时候就与其它计息,以及业务流程整合在一起来考虑,如果中途加入这个需求,那改起设计来会比较费劲,改起代码来更是难上加难。

    最后,我们再来说说计提,这个也和利息有关。计提常用于利息支出,比如说利息支出是5211,5字头,即是一个用于营业收支的损益类的科目。计提的会计分录中,对应的科目是应付利息2611, 2字头,是一个负债类的科目。所以说,计提的含义就在于,虽然当前客户利息并未产生(是结息的时候才产生),但是这笔利息(尤其是整存整取的定期利息)迟早是会产生的,所以这里预先计算,或者说估算出营业支出,计到负债的科目上(负债嘛,本来不属于银行的钱,迟早是要被取走的钱),然后到这类账户结息的时候,就直接从应付利息中支出,计到客户账户上,而不走利息支出这个科目了。看懂了吧,这里其实也就包含了管理会计中的概念,实际上是产生一个提前测算成本的动作。诸位搞IT的朋友们,你们看过《会计学原理》吗?

    5.3 储蓄/对公

    这部分模块一般没太多可讲的,通常的设计,都是搞个主文件,保存针对每个账户的信息(比如说账号,账户余额,当前积数什么之类的,总之就是与账户有关的信息),然后再搞个账户明细,用来记录每个账户发生过的业务。听闻有的系统设计,不知道是不是考虑到锁表的问题,计划取消主文件,直接上明细,愕然之余只能感叹自己见识浅薄,因为我总觉得明细要考虑冲账的问题,在读取上不如主文件一下搞定那么畅快。而且主文件可以有锁表保护,可以更好的保障数据的正确性。

    所以私底下,我还是很推崇这种“主+明细”的设计方式。以前曾经很无奈地见过有人在新增业务模块时,把主文件和明细混在一起来搞,于是整个业务流向怅然若失,需求有变动时改动几乎无从下手,若非我多年功力,是断断不可能在加两天班后就理顺通过测试的。

    说起储蓄呢,又忍不住再提一下招行,不可否认,它的一卡通做得真的挺好,本外币,定活期,一张卡全部搞定。我以前就经常把活期转成三个月定期。根据我本人看法,三个月定期从利率差与时间存放差上来说,性价比是最高的,也就是说一年期利率虽然高,但很难保障这点钱在一年内不用。所以推荐大家把5K以上的存款转成三个月定期,一般忍忍也就可以拿到利息了,当然了货币基金也是一个不错的选择。还有一次自做聪明搞了个一年期的零存整取,性价比不高,而且还得到柜台去办取款手续,把自己麻烦死了,不推荐使用。

    扯远了,其实本来是想说,活期、定期、外币账户,这些都是一个又一个的账户,而在招行的设计之中,这些账户,都会与我们的那一张小小的卡片关联起来。换句话说,人家的卡号,应该只含具体的卡的信息,比如说卡的有效期,密码,磁道信息什么之类的,不直接对应某个具体账户的;而各个具体账户则应该会有一个与卡号的对应关系。然后到寄对账单的时候啊,打电话介绍买保险等等附加服务的时候,就还是根据卡号来提供服务。不过还是要根据账户的资金流动来分析消费习惯,以及贡献度的高低等等。

    至于怎么实现,就根据各位自己的核心系统慢慢体会,不过这么多年了,也可能大部分银行都实现了这种功能或者是类似的一卡通,那就当我这段没有讲过吧,总之我觉得这种理念很好很强大,让我用得觉得很方便。

    至于对公,好象就更加没什么可说的了。

    5.4 客户信息

    客户信息,卡号,账户号,这三者是层层细化的关系。所以说,整合好三者的关系也是一个不容易的事情。

    在我见过的几套系统之中,最常见的问题,就是同一个客户对应多个客户信息。这通常又是个历史遗留问题,比如在手工或单机年代,开户时对于身份证明证件要求不是很严格,一个人可能开了很多账户,还可能是用化名开的账户。在移植上线的时候,常常由于重要信息不齐,又要考虑客户层面的因素,很少能强制性补齐客户资料,通常只能在移植时自动生成一些客户信息,这样就造成了很多冗余,而且也不好再做深层的数据挖掘和客户分析。相比较而言,新开立的分行可能这种情况会好一点,而且面对的客户高端一点的,又会更好一点。

    在新系统上线,做数据移植的阶段,一般客户信息的问题是最先体现出来的,通常新系统会要求得比较理想化,而实际情况千奇百怪。这里说说常见的,比如说新系统一般会要求证件号码唯一,但是因为很多客户的证件信息缺失,所以这个号码唯一可能会有困难;再比如说有时可能会出现证件号码重复,而且还真的不是同一个人。

    总之这些问题,它不是新系统的错,也不能完全说是旧系统的错,最关键的是在移植的时候如何处理利用好这部分客户信息。

    再一个问题,就是客户信息的更新。个人认为最好能有一个有效的途径来更新客户信息,尤其是工作单位,电话号码,对于很多流动人员来说,经常会变换。如果每次都要来柜台更新,我想那基本上就可以认为它是形同虚设了。

    可以说,随着现在以客户为中心的概念的提出以及越来越多的实现,客户信息这个模块也应该会越来越受到重视,以前设计的表结构应该会有些不够用了。目前如果没有新系统要上的同行们,恐怕是要等着改结构加字段了,保重。

    5.5 贷款

    很多地方都会把一般的商业贷款按揭贷款消费贷款(比如车贷、分期付款之类的,总之有点类似于按揭贷款的)区分开来,这样自然有它的道理。我在这里只谈我个人的设计方案。

    现在的商业贷款常常采用一笔发放,一笔回收的概念(当然有时会有提前还款,但不象按揭贷款这样有个具体还款计划),然后用合同号,或是借据号做为贷款的一个类似于唯一关键字这样的东西。但是有时公司的商业行为中,一个大项目里会包含多个子项目,然后对应不同的子合同,这些合同对应的贷款之前其实都是有关联的,尤其是在算逾期什么之类的时候,有的是一逾全逾,有的又不是。所以我个人觉得,贷款最好做成多笔发放,多笔回收的形式,发放与回收不必一一关联。但最好在贷款录入时(这时不一定已放款),就录入相应的还款计划

    贷款的账号,最好与具体的业务信息剥离,类似于储蓄里面“一卡通”的概念一样,每个贷款,有它自己独立的贷款号,然后正常、逾期、两呆,以及相应的利息账号都与这个贷款号关联起来,便于以后的跟踪追查。

    而对于按揭贷款来说,因为期限长(常常是二三十年),而且比较具有规律性,所以一般就不用列出还款计划的明细了。不过要注意,一般按揭贷款的首月还款是按天算息的,稍微注意一下就可以了。

    最后,特别强调提出一点,见过两家行,都推出过“等本等息”这种经典的业务产品,也就是客户每月按等额法算出的金额还款,但本金的计算则按等本的方式来算。

    这里要大声疾呼,这种东西从原理上来说就已经是错误的!因为同样金额,同样期限的贷款,等额法的利息是要大于等本法的利息的。

    等本法计算方便,理解简单;而等额法是数学家们经过精确的计算,推导出公式,最后计算出的一种还款方法。也就是每个月的还本、还息都要严格按照计算出的公式,这样才能达到等额的效果。

    试想想,这个月还了一定的本金之后,下个月计算出的利息就不一样了吧,这时要求下个月还的本金与还的利息加起来还是和这个月的一样多,而且还要求每个月还的本金加上利息都是一样多。所以,除非是数学学得特别好的同学,咱们一般的程序员不要妄想自己能推导出公式来,照着公式算就行了。如果强行按等额法计算出的钱来制订还款计划,又按等本法的方式还计算每期还款本金,虽然是方便了,但是在每年利率变更,重算利息时,必然会导致利息总和由等额法的利息渐渐趋近于等本法的利息,也就是总利息额将会越来越少,于是要么在本金与利息的问题上无法自圆其说,要么可能会出现利率上调还款金额反降,甚至负利息的问题,不可不查。

    5.6 清算与结算

    清算与结算本来是两种业务,不过因为结算中通常又会包括清算,要分成两小节,每小节又说不了太多话,所以干脆放在一起算了,而且这一节只谈流程,不讲设计,这种业务流程理顺了自然就可以设计了。

    先约定一下,商业银行的级别,一般是 分行—支行两级,有的可能还会有储蓄所这种第三级。简化起见,暂时就分两级来说吧。如果对应到信用社,那就是联社营业部—信用社营业部。分社一级省略。

    先从结算说起,这里的结算业务,指的就是跨行转账,至少我是打算这么说。每家商业银行,都会在当地的人民银行有一个资金账户,可以理解为结算业务用的备付金账户。然后在自己行内,也会开立一个与之对应的“上存人行款项”的账户。理论上,人行的这个账户和我们自己行内的这个账户,表达的都是“该银行存放在人民银行的钱”的这个意思,所以金额也应该相等。那么,这两个账户在不同的银行(也即不同的系统中),如何保障它的一致性?这一般就是通过日终,营业终了时的对账来保障。所以对账是很重要的,这个后面再说。

    至于结算业务的流程,先从遥远的手工账/单机账年代说起吧。在那个时候,结算的途径、概念、术语可以说是五花八门,什么先直后横,先横后直,提出借方,提出贷方,提入借方,提入贷方,信汇,电汇等等等等,不把人转晕誓不罢休。

    现在好象大小额支付横空杀出,倒是简化了不少。当然也还有行间转账,同城支付,省金融平台,不过概念上渐渐趋向统一化,先不多说,先谈谈当时我理解中的流程:

    • 首先如果要转账,我们要在柜台前填一份一式五联的单(一定要用力填哟,不然最后一张纸上看不到什么字迹的),然后这笔钱就从我们的账户上扣下来,划到银行内部的某个往来账户上了。
    • 然后这些单据,再手工传递到上一级,上一级再手工传递到人行(当然,也可能上一级就是人行,这里不要太较真),每传一次,这笔资金都会在当前做业务的这一个银行的往来账户中流动,最后通过人行,流到你想转入的银行中,那个你手工填的单,也流到那家银行中。最最后,转入行的业务人员核对单据,账号,户名都没问题,这笔钱就从往来账户划到我们所填的转入账户上去了。

    在这些过程中,结算的同时就已进行了清算,资金的流向是A银行的某支行àA银行的当地分行àA地人行àB地人行àB银行当地分行àB银行的某支行也就是每一笔转账,在行间的这一步,都是通过它们在人行的资金往来账户,实现了资金的流动。

    如果是上述的资金流向,就叫先直后横

    如果是A地人行àB银行A地分行àB银行B地分行àB银行某支行这种方式,就叫先横后直

    这些单据的传递,都是手工的,或者说是落地的。如果是用信件的方式传递,那就是信汇;如果是用打电报的方式传递,那就是电汇。手工的传递都是有场次的,比如一天两场,或是一天一场之类的。所以这个转账的效率有多快,我就不说了。

    现在科技进步了,手段丰富了,社会于是也就和谐的。先从我个人较为欣赏的大额支付说起。我一向认为大额这个业务设计得是相当的合理,因为资金是点对点,清算行对清算行,大大缩短了流程,更重要的是,信息的传递是自动的。还是上述的CASE,假设转出行与转入行都开通了大额业务,那么资金的流向是:

    A银行的某支行à人行àB银行的某支行

    原则上是这样的实现,当然行内的设计怎么处理我们就不多考虑了。行内当然也可以设计成为先从A银行的支行转到上级分行然后再发出,总之人行收到一笔大额的转账信息之后,是会自动、直接发向指定的转入行(假设转入行也开通了大额业务的话)

    大额系统的对账,不考虑具体的客户账户,只考虑清算行。通俗的说,人行只管A银行今天给B银行转过去多少钱,转过去了,人行就不管了。至于B银行什么时候把这笔钱入到客户账户中,那是B银行的事,人行不管。听起来责任还是很清晰的吧,而且这样也有助于减少账户锁表而造成的行间转账失败。

    因为大额的这种设计,所以实际转账中,几乎是实时的。我从某地信用社转到异地招行,在柜台还没最后签字,收款短信已经来了。

    因为大额业务发生的时候,是支行对支行的,所以每发生一笔业务之后,实际上这笔资金是暂时体现在该支行的某个行间往来账户上。所以每天大额业务结束后,还需要按清算的流程,将这笔资金按往、来分别清算到上一级分行(或是总行吧,总之就是当地的最高节点),然后分行与人行发下来的电子对账文件进行对账,检查汇总往、来数、金额是否相等。如果相等,那就可以把往来一轧差,转出多的时候就从存放在人行的账户里扣钱,转入多的时候就往那个账户里加钱。

    至于这个清算的步骤,通常还是由手工发起,不过这里的手工,就不是指传递单据,而是指运行程序。当然,清算程序也可以自动运行,这个根据系统的不同,要求的不同,自行调整设计。

    5.7 额度控制

    和计息类似,可能有的系统没有把额度单列为一个模块来处理,而是仅仅作为业务模块之中的一个判断项。早期的业务中,的确可以这样处理。不过随着现在金融产品的不断推出,我个人认为还是把额度拿出来单独搞一下会更好处理一点。

    比如说,一个账户,可能会有几次冻结,也能会有多项额度控制,每次的解冻,又或者是解除控制,都可能会对账户的额度造成不同的影响,如果夹杂在业务模块中,字段的设计,状态的控制可能都会有些问题,单独整成一个模块,或者说是一个大公函,在账务交易(或是账务模块中)的时候,用额度模块来进行一下判断,可以更方便的检测账户的可用额度是否足够。

    另外,一些账户相关的透支什么的,也可以比较好的按客户来处理,而不是针对每个账户设置是否允许透支。以至于循环授信额度,这些概念都可以拿出来使用,简单的来说,有点类似于储蓄卡向贷记卡的管理方式倾斜,不过我没做过贷记卡,所以这里也提不出太多东西,只好拿个概念出来大家一起参详一下。

    5.8 冲账

    本着想到哪里就说到哪里的原则,刚才突然想起冲账还没有说,那么这里就说说冲账。

    冲账的概念前面已经提过,这里我们指的,就是红字冲账。因为蓝字冲账就是再做一笔别的账务,从IT人员的角度出发,其实是另一个合法的正交易,不能算是冲账。

    在设计程序的时候,只要是财务类的业务,就一定要考虑冲账的问题,不能偷懒,不能妄想测试人员会遗漏。就算别人忘记了测试,如果在真实业务中发生了问题,是很麻烦的,所以要养成良好的设计、测试的习惯。(这里不谈编码,因为设计好了自然就会写代码的)

    关于冲账的实现,我知道的有两种方式:

    • 第一是正反交易的概念。也就是普通的账务交易,称之正交易。每一个正交易,都需要有一个与之匹配的反交易,如果是按交易码来管理的话,可能会有一个标准来定义反交易的交易码,比如说正交易码加上5000就是相应的反交易之类的。(这里只是随便举个例子,比如说0001表示取款,那么5001就表示取款的反交易)因为冲账在账务处理上,具有一些共性,比如说都是按原来的财务的会计分录,只是金额为负发生账务即可,所以有可能会有一些公共函数来调用,不过总的来说,都是小函数的概念。这种设计的缺点很显而易见,就是交易码,代码量都要翻倍。业务人员在冲账的时候也需要稍微算算交易码,有可能会输错。好处也是很明显的,就是程序之间互相不影响,修改维护都很容易
    • 第二种设计思路就是大函数的概念,也就是使用一个交易来实现冲账。因为前面说过,冲账业务具有一些普遍的共性,就基本原则来说,找到这笔正交易最初的账务,就可以了。所以使用一个大交易来实现。至于各个业务模块冲账后,在财务处理完之后的业务冲账,那可能就需要不断的在这个大交易中挂上各类外挂了。这种设计的缺点也很明显,就是维护起来很不方便,因为相当于把业务模块的冲账都集成到一个大交易中,在版本控制,大量测试的时候可能会有较多冲突。好处就是不占用交易码,也可以减少很多代码量,对于很标准的冲账,甚至不需要特别去考虑冲账的问题。(不过怕的就是不那么标准的冲账)

    这两种方法各有优缺点,不知道大家的系统中,使用的哪种方式。这里我提出一个集合两者的第三种方法,一起来参详一下:

    仍然考虑以大交易为主,不过大交易按某个参数表,来决定调用业务模块中的部分程序解决业务模块的冲账问题。如果是非常标准的冲账,就不需要刻意写冲账程序。如果是不标准的冲账,就在参数表中按设计中自已定义好的各类标识符,使大交易可以判断出何时调用业务模块中的冲账子程序(这些冲账子程序可以随时新增,名字也可以自定义,总之是在参数表中来定义)。至于大交易与冲账子程序中间的程序入口参数的传递,因为各个业务模块要求都有所不同,所以可考虑使用一个大字符型字段,或是数据队列传递字符流的方式来解决

    5.9 其它

    暂时先想到这么多,其实还有其它的东西。比如说日终批处理,不过做到这一块的同行们想来不是技术骨干就是业务能手,也就没必要看这份入门级的东西了。还有拆借,贴现,不过这部分在核心系统里面占的份量很小,业务理解起来也不难,抓住一个熟悉业务的人多问问就问出来了。还有代理业务,不过这种业务的设计也多半是主+明细的方式(比如说代理单位的汇总信息,以及相应代理业务的明细记录),麻烦的可能反而主要在数据的交互上,也就是什么倒盘啊,信息录入啊什么的,又或者是具体的程序运行效率上,和这个整体设计的关系倒不大。

    关于批处理,我做得比较多,还是再简单说两句。一般来说,会要求维护人员按各自的业务模块,维护批处理中的相应程序。不过最后,仍然需要一个总体上能把握的人来协调调度。批处理的程序大致上可以分为三种功能:

    实现各类日终自动业务。比如说到期自动扣款(用过信用卡的朋友们应该深有体会吧),贷款的形态转移,储蓄结息(居然现在变成一年四结,有些先进的国外系统还要天天计提,我只能说系统的设计出发点各有不同啊),可能还会有上面提到的日终清算。当然,还包括了各类的日初业务初始化。

    实现账务模块数据向总账模块数据的转换,也就是更新总账模块的数据。严谨一点的系统,在更新了总账模块的数据之后,还会用程序来检查一下总账模块的数据与业务模块中的数据是否匹配,一致。(也就是传说中的总分核对)

    生成各类报表。这部分可能主要是从总账模块中出,也可能需要综合一下业务模块中的数据。

    批处理的发起,是由固定的操作人员来执行,没见过设计成按时间点自动运行的。

    刚才说到批处理的三项基本功能,而其实在各类功能中,程序的运行顺序还是颇有讲究,不能随意乱放,否则可能会出现无法预知的问题。

    批处理的排障,也是一个比较痛苦麻烦的事情,这里真诚的建议各位维护批处理的同行在有大模块上线前,做好心理准备,多多祈祷,实在不行还可以试试拜拜土地。

    四,银行新核心系统账务处理流程介绍

    百度文库 银行新核心系统账务处理流程介绍

    帐务处理流程图

    业务处理流程

    业务处理流程——

    • 存款/取款
    • 贷款/还款
    • 凭证
    • 现金
    • 资金
    • 股金
    • 外汇
    • 本汇票
    • 银承贴现
    • 储值卡
    • 信用卡
    • 客户管理
    • 公共管理
    • 机构柜员管理
    • ...

    image.png

    业务凭证 ——

    • 支付凭证(Payment)
    • 账单(Invoice)
    • 支付应用(Payment-application)【=核销】
    • 调账单(Acctg_Trans/Acctg_Trans_Entry)

    支付应用=核销

    调账单

    会计引擎

    凭证拆分规则

    支付

    账单

    典型场景-现金存款

    五,现金、资金、资产、资本

    要点——
    现金 = M0货币
    资金 = 拥有的金钱(现金+存款)
    资产=资产负债表的左侧(现金+存款+其他财产)
    资本=资产负债表的右侧(债务资本,权益资本)

    • 资产,是企业用于从事生产经营活动以为投资者带来未来经济利益的经济资源,出现在资产负债表的左侧,归企业所有。企业的所谓法人财产权,就是指企业对其控制的资产拥有的所有权。
    • 资本,是企业为购置从事生产经营活动所需的资产的资金来源,是投资者对企业的投入,出现在资产负债表的右侧,它为债务资本与权益资本,分别归债权人和公司所有者(股东)所有,企业对其资本不拥有所有权。
    • 资金,广义上讲,与“资产”的概念是一致的,但它有缩小范围的概念,如特指货币资金,或是特指营运资金。

    1,现金,是中国人民银行依法发行的流通中的人民币,包括纸币和硬币。现金是货币的一部分,货币包括现金和存款货币,是货币供应中是最活跃的一个层次。

    2,我国资金是社会主义再生产过程中通过不断运动保存并增加其自身价值的价值。是社会主义公有资产的价值形态,是社会主义国家和企业扩大再生产,满足全社会劳动者日益增长的物质和文化需要的手段,体现国家、企业、劳动者个人三者在根本利益一致基础上的关系。

    资金的分类方式主要有:

    • ①按分配的形式,可分为通过财政收支形式而分配的财政资金和通过银行信贷形式而分配的信贷资金。
    • ②按用途可分为用于基本建设的资金和用于生产经营活动的资金。
    • ③按在再生产过程中的周转情况,可分为表现为房屋、机器设备等的固定资金和表现为原材料、在制品、制成品、商品、银行存款等的流动资金。

    无论是哪一种形式的资金,都必须参与社会主义的再生产过程,处在不断的运动之中。资金只有在运动中,才能保存价值并使原有的价值得到增殖



    作者:大圣2017
    链接:https://www.jianshu.com/p/f527c226e101
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    展开全文
  • 操作系统银行家算法模拟实现(C语言版)

    万次阅读 多人点赞 2020-05-23 11:12:44
    通过编写一个模拟动态资源分配的银行家算法程序,进一步深入理解死锁、产生死锁的必要条件、安全状态等重要概念,并掌握避免死锁的具体实施方法。 二、实验内容 (1)模拟一个银行家算法: 设置数据结构 设计安全...

    目录

    一、实验目的        

    二、实验内容

    三、实验要点说明

    银行家算法实例

    程序结构

    四、实验代码

    五、实验运行结果


    一、实验目的        

           通过编写一个模拟动态资源分配的银行家算法程序,进一步深入理解死锁、产生死锁的必要条件、安全状态等重要概念,并掌握避免死锁的具体实施方法。

    二、实验内容

    • (1)模拟一个银行家算法: 设置数据结构 设计安全性算法
    • (2) 初始化时让系统拥有一定的资源
    • (3) 用键盘输入的方式申请资源
    • (4)如果预分配后,系统处于安全状态,则修改系统的资源分配情况
    • (5)如果预分配后,系统处于不安全状态,则提示不能满足请求

    三、实验要点说明

    数据结构

    •  可利用资源向量   int  Available[m]   m为资源种类
    • 最大需求矩阵        int  Max[n][m]     n为进程的数量
    • 分配矩阵               int  Allocation[n][m]
    • 还需资源矩阵        int  need[i][j]=Max[i][j]- Allocation[i][j]
    • 申请资源数量        int  Request [m]  
    • 工作向量               int  Work[m]    int  Finish[n]

    银行家算法bank()函数

    Requesti:进程Pi的请求向量。   0<=j<=m-1

    • (1) 若 Requesti[j] ≤ Need[i,j],转向(2),否则出错。
    • (2) 若 Requesti[j] ≤ Available[j],转向(3),否则等待。
    • (3) 系统试探着把资源分配给进程Pi,修改下面内容:
    •       Available[j] = Available[j] – Requesti[j];
    •       Allocation[i,j] = Allocation[i,j] + Requesti[j];
    •       Need[i,j] = Need[i,j] –Requesti[j];
    • (4) 试分配后,执行安全性算法,检查此次分配后系统是否处于安全状态。若安全,才正式分配;否则,此次试探性分配作废,进程Pi等待。

    安全性算法safe()函数

    • (1) 初始化:设置两个向量Work(1×m)和Finish(1×n)
    •       Work – 系统可提供给进程继续运行所需各类资源数,初态赋值Available
    •       Finish – 系统是否有足够资源分配给进程,初值false.
    • (2) 从进程集合中满足下面条件进程:
    •       Finish[i] = false;  Need[i,j] ≤ Work[j];
    •       若找到,执行(3),否则,执行(4)。
    • (3) 进程Pi获得资源,可顺利执行,完成释放所分配的资源。
    •       Work[j] = Work[j]+Allocation[i,j];  Finish[i] = true;  go to (2).
    • (4) 若所有进程Finish[i] = true,表示系统处于安全状态,否则处于不安全状态。

    先对用户提出的请求进行合法性检查,即检查请求的是否不大于需要的,是否不大于可利用的。 若请求合法,则进行试分配。最后对试分配后的状态调用安全性检查算法进行安全性检查。 若安全,则分配,否则,不分配,恢复原来状态,拒绝申请。

    银行家算法实例

    假定系统中有五个进程{P0、P1、P2、P3、P4}和三种类型资源{A、B、C},每一种资源的数量分别为10、5、7。各进程的最大需求、T0时刻资源分配情况如下所示。

    试问:      

    • ①T0时刻是否安全?      
    • ② T0之后的T1时刻P1请求资源Request1(1,0,2)是否允许?      
    • ③ T1之后的T2时刻P4请求资源Request4(3,3,0)是否允许?      
    • ④ T2之后的T3时刻P0请求资源Request0(0,2,0)是否允许?

    ① T0时刻是否安全? 工作向量Work.它表示系统可提供给进程继续运行所需要的各类资源的数目

    (1) T0时刻安全性分析

    存在安全序列{P1, P3, P4, P0, P2},系统安全。

    (2) T0之后的T1时刻P1请求资源Request1(1,0,2)可否允许?

    • ①Request1(1,0,2) ≤ Need1(1,2,2),P1请求在最大需求范围内
    • ②Request1(1,0,2) ≤ Available1(3,3,2),可用资源可满足P1请求需要
    • ③假定可为P1分配,修改Available,Allocation1,Need1向量
    •     Available(2,3,0) = Available(3,3,2)-Request1(1,0,2);
    •     Need1(0,2,0) = Need1(1,2,2)-Request1(1,0,2);
    •     Allocation1(3,0,2) =Allocation1(2,0,0)+Request1(1,0,2);
    • ④利用安全性算法检查试探将资源分配后状态的安全性

    存在安全序列{P1, P3, P4, P0, P2},所以试探将资源分配给进程P1后的状态是安全的,可将资源分配给进程P1。

    ③ T1之后的T2时刻P4请求资源Request4(3,3,0)是否允许?

    • Request4(3,3,0)≤Need4(4,3,1),P4请求在最大需求范围内。
    • Request4(3,3,0)≤Available(2,3,0)不成立,即可用资源暂不能满足P4请求资源需要,P4阻塞等待。

    P4请求资源Request4(3,3,0)不允许。

    ④ T2之后的T3时刻P0请求资源Request0(0,2,0)是否允许?

    • Request0(0,2,0)≤Need0(7,4,3);
    • Request0(0,2,0)≤Available(2,3,0);

    系统暂时先假定可为P0分配资源,并修改有关数据,如下图所示:

    进行安全性检查:可用资源Available(2,1,0)已不能满足任何进程的需要,故系统进入不安全状态,此时系统不分配资源。

    程序结构

    程序共有以下五个部分:

    • (1).初始化init():输入进程数量、资源种类、资源可利用量、进程资源已分配量、进程最大需求量
    • (2).当前安全性检查safe():用于判断当前状态安全
    • (3).银行家算法bank():进行银行家算法模拟实现的模块
    • (4).显示当前状态show():显示当前资源分配详细情况
    • (5).主程序main():逐个调用初始化、显示状态、安全性检查、银行家算法函数,使程序有序的进行

    四、实验代码

    #include<stdio.h>
    #include<stdlib.h>
    
    #define False 0
    #define True 1
    
    /********主要数据结构********/
    char NAME[100]={0};//资源的名称
    int Max[100][100]={0};//最大需求矩阵
    int Allocation[100][100]={0};//系统已分配矩阵
    int Need[100][100]={0};//还需要资源矩阵
    int Available[100]={0};//可用资源矩阵
    int Request[100]={0};//请求资源向量	
    int Work[100]={0};//存放系统可提供资源量 
    int Finish[100]={0}; //标记系统是否有足够的资源分配给各个进程 
    int Security[100]={0};//存放安全序列
    
    int M=100;//进程的最大数
    int N=100;//资源的最大数
    
    /********初始化数据:输入进程数量、资源种类、各种资源可利用数量、
    各进程对资源最大需求量、各进程的资源已分配数量等。********/
    void init()
    {
    	/* m为进程个数,即矩阵行数,n为资源种类,即矩阵列数。*/
        int i,j,m,n;
    	int number,flag;
    	char name;//输入资源名称
    	int temp[100]={0};//统计已经分配的资源
    	//输入系统资源数目及各资源初试个数 
    	printf("系统可用资源种类为:");
    	scanf("%d",&n);
    	N=n;
    	for(i=0;i<n;i++)
    	{
    		printf("资源%d的名称:",i);
    		fflush(stdin);  //清空输入流缓冲区的字符,注意必须引入#include<stdlib.h>头文件
    		scanf("%c",&name);
    		NAME[i]=name;
    		printf("资源%c的初始个数为:",name);	
    		scanf("%d",&number);
    		Available[i]=number;
    	}
    	
    	//输入进程数及各进程的最大需求矩阵 
    	printf("\n请输入进程的数量:");	
    	scanf("%d",&m);
    	M=m;
    	printf("请输入各进程的最大需求矩阵的值[Max]:\n");
    	do{
    		flag = False;
    		for(i=0;i<M;i++)
    			for(j=0;j<N;j++)
    			{
    				scanf("%d",&Max[i][j]);
    				if(Max[i][j]>Available[j])
    					flag = True;				
    			}
    		if(flag)
    			printf("资源最大需求量大于系统中资源最大量,请重新输入!\n");								
    	} while(flag);
    	
    			
    	//输入各进程已经分配的资源量,并求得还需要的资源量 
    	do{
    		flag=False;
    		printf("请输入各进程已经分配的资源量[Allocation]:\n");
    		for(i=0;i<M;i++)
    		{
    			for(j=0;j<N;j++)
    		  	{
    				scanf("%d",&Allocation[i][j]);
    				if(Allocation[i][j]>Max[i][j])  
    					flag=True;				
    				Need[i][j]=Max[i][j]-Allocation[i][j];
    				temp[j]+=Allocation[i][j];//统计已经分配给进程的资源数目
    		  	}
    		}
    		if(flag)
    			printf("分配的资源大于最大量,请重新输入!\n");		
    	}while(flag);
    	
    	//求得系统中可利用的资源量 
    	for(j=0;j<N;j++)
    		Available[j]=Available[j]-temp[j];
    }
    
    /********显示资源分配矩阵********/
    void showdata()
    {
    	int i,j;
    	printf("*************************************************************\n");
    	printf("系统目前可用的资源[Available]:\n");
    	for(i=0;i<N;i++)
            printf("%c  ",NAME[i]);
    	printf("\n");
    	for(j=0;j<N;j++)
            printf("%d  ",Available[j]);
    	printf("\n");
    	printf("系统当前的资源分配情况如下:\n");
    	printf("            Max   	 Allocation    Need\n");
    	printf("进程名     ");
    	//输出与进程名同行的资源名,Max、Allocation、Need下分别对应 
    	for(j=0;j<3;j++){
    		for(i=0;i<N;i++)
    			printf("%c  ",NAME[i]);
    		printf("     ");
    	}
    	printf("\n");
    	//输出每个进程的Max、Allocation、Need 
    	for(i=0;i<M;i++){
    		printf(" P%d        ",i);
    	    for(j=0;j<N;j++)
    			printf("%d  ",Max[i][j]);
    		printf("     "); 
    		for(j=0;j<N;j++)
    			printf("%d  ",Allocation[i][j]);
    		printf("     "); 
    		for(j=0;j<N;j++)
    			printf("%d  ",Need[i][j]);
    		printf("\n");
    	}
    }
    
    /********尝试分配资源********/
    int test(int i) //试探性的将资源分配给第i个进程 
    { 
    	for(int j=0;j<N;j++)
    	{
    		Available[j]=Available[j]-Request[j];
    		Allocation[i][j]=Allocation[i][j]+Request[j];
    		Need[i][j]=Need[i][j]-Request[j];
    	}
    	return True;
    }
    
    /********试探性分配资源作废********/
    int Retest(int i) //与test操作相反 
    { 
    	for(int j=0; j<N; j++)
    	{
    		Available[j] = Available[j] + Request[j];
    		Allocation[i][j] = Allocation[i][j] - Request[j];
    		Need[i][j] = Need[i][j] + Request[j];
    	}
    	return True;
    }
    
    /********安全性算法********/
    int safe()
    {
    	int i,j,k=0,m,apply;
    	//初始化work 
    	for(j=0;j<N;j++)
            Work[j] = Available[j];
        //初始化Finish 
        for(i=0;i<M;i++) 
        	Finish[i] = False;
    	//求安全序列 
    	for(i=0;i<M;i++){ 
    		apply=0;
    		for(j=0;j<N;j++){
    			if(Finish[i]==False && Need[i][j]<=Work[j])
    			{   
    				apply++;
    				//直到每类资源尚需数都小于系统可利用资源数才可分配
    				if(apply==N)
    				{  
    					for(m=0;m<N;m++)
    				        Work[m]=Work[m]+Allocation[i][m];//更改当前可分配资源
    					Finish[i]=True;
    					Security[k++]=i;
    					i=-1; //保证每次查询均从第一个进程开始		
    				}
    			}
    		}
    	}
    	
    	for(i=0;i<M;i++){
    		if(Finish[i]==False){
    			printf("系统不安全\n");//不成功系统不安全
    			return False;
    		}
    	}
        printf("系统是安全的!\n");//如果安全,输出成功
        printf("存在一个安全序列:");
    	for(i=0;i<M;i++){//输出运行进程数组
    		printf("P%d",Security[i]);
    		if(i<M-1) 
    			printf("->");
    	}
    	printf("\n");
    	return True;
    }
    
    /********利用银行家算法对申请资源进行试分********/
    void bank()
    {
    	int flag = True;//标志变量,判断能否进入银行家算法的下一步 
    	int i,j;
    
    	printf("请输入请求分配资源的进程号(0-%d):",M-1); 
        scanf("%d",&i);//输入须申请资源的进程号
        
    	printf("请输入进程P%d要申请的资源个数:\n",i);
    	for(j=0;j<N;j++)
    	{
    		printf("%c:",NAME[j]);
    		scanf("%d",&Request[j]);//输入需要申请的资源
    	}
    	
    	//判断银行家算法的前两条件是否成立 
        for (j=0;j<N;j++)
    	{
    		if(Request[j]>Need[i][j])//判断申请是否大于需求,若大于则出错
    		{ 
    			printf("进程P%d申请的资源大于它需要的资源",i);
    			printf("分配不合理,不予分配!\n");
    			flag = False;
    			break;
    		}
    		else 
    		{
                if(Request[j]>Available[j])//判断申请是否大于当前可分配资源,若大于则出错
    			{                         
    				printf("进程%d申请的资源大于系统现在可利用的资源",i);
    				printf("\n");
    				printf("系统尚无足够资源,不予分配!\n");
    				flag = False;
    				break;
    			}
    		}
        }
        //前两个条件成立,试分配资源,寻找安全序列 
        if(flag) {
    		test(i); //根据进程需求量,试分配资源 
    		showdata(); //根据进程需求量,显示试分配后的资源量 
    		if(!safe()) //寻找安全序列
    		{
    			Retest(i);
    			showdata();
    		}
        }
    }
    
    
    int main()//主函数
    {	
    	char choice;
    	printf("\t---------------------------------------------------\n");
    	printf("\t||                                               ||\n");
    	printf("\t||               银行家算法的实现                ||\n");
    	printf("\t||                                               ||\n");
    	printf("\t||                                               ||\n");
    	printf("\t||                     在此输入个人姓名:******  ||\n");
    	printf("\t||                                               ||\n");
    	printf("\t---------------------------------------------------\n");
    	init();//初始化数据
        showdata();//显示各种资源
        //用银行家算法判定系统当前时刻是否安全,不安全就不再继续分配资源 
    	if(!safe()) exit(0);
    	
    	do{
    		printf("*************************************************************\n");
    		printf("\n");
    		printf("\n");
    		printf("\t-------------------银行家算法演示------------------\n");
    		printf("                     R(r):请求分配   \n");	
    		printf("                     E(e):退出       \n");
    		printf("\t---------------------------------------------------\n");
    		printf("请选择:");
    		fflush(stdin);  //清空输入流缓冲区的字符,注意必须引入#include<stdlib.h>头文件
    		scanf("%c",&choice);
    		switch(choice)
    		{
    			case 'r':
    			case 'R':
    				bank();break;			
    			case 'e':
    			case 'E':
    				exit(0);
    			default: printf("请正确选择!\n");break;
    		}
    	} while(choice);
    }
    
    
    

    五、实验运行结果

    展开全文
  • 银行ECIF系统

    千次阅读 2020-09-27 14:18:12
    ECIF是企业级客户信息整合系统(Enterprise Customer Information Facility),系统主要的目的是整合银行各个系统的客户信息,比如包括客户基本信息、客户关系、客户产品等等。我理解整合后的系统属于基础信息系统。 ...
  • C++个人银行账户管理系统

    千次阅读 2022-05-07 00:07:56
    采用C+ +面向对象的程序设计方法开发基于ATM的个人银行账户管理系统,根据大家的日常经验设计、实现以下功能(但不限于) : (1) 管理个人账户Account (基类)基本信息,比如帐号、密码、姓名、性别、住址、电话、身份证...
  • 2012版的要求(见下图1) USBKEY有抗侧信道攻击能力,就是USBKEY作为密码模块达到二级,但安全芯片可以是一级。 2020版的要求(见下图2) USBKEY的加密芯片有抗侧信道攻击能力,那就是安全芯片要达到二级。 图...
  • 业务: 存储中心(核心业务数据、数据仓库)。 处理中心(核心业务逻辑)。 管理: 安全认证和安全管理中心。 全行系统管理中心。 ...联络中心(人总行、...第一层为渠道层,这里为银行的业务系统,每个系统进...
  • 银行ATM存取款系统(C语言实现)

    万次阅读 多人点赞 2021-11-21 20:40:14
    银行ATM存取款系统 三、设计内容(主要技术关键的分析、解决思路和方案比较等) 银行ATM存取款系统 银行ATM存取款系统业务描述如下: 银行ATM存取款系统能为用户提供存款、取款、查询、转账和修改密码的功能。为了模
  • 一、系统开放性  计算机技术发展的潮流之一就是系统的开放性和64位技术。为了使系统具有更强的兼容性和可扩展性,系统应设计成开放式的网络业务系统。...商业银行来讲,本身没有专业银行的历史包袱,能较快
  • 操作系统-资源分配银行家算法

    千次阅读 2020-11-16 20:43:09
    通过本次实验,使学生加深死锁概念的理解和掌握,并培养学生操作系统课程的兴趣与高级语言设计的能力。 二、 实验内容 1、要求 设计五个进程{P0···P4}共享三类资源{A,B,C}的系统,每一种资源数量为10,5,7...
  • 支付清算系统是经济金融活动的基础性支撑。支付、清算体系建设是金融理论与实践的重点课题...同时也让对银行核心感兴趣的企业,多一些业务和技术上的了解。总有人要做的,那就由愚笨的笔者来抛砖引玉吧!笔者小小的.
  • 银行审批系统简记

    千次阅读 2018-01-17 22:16:01
     审查内容信用卡申请审批模块具有申请人信息进行黑名单、年龄、收入、主附卡关系、重复申请检查,完成信贷参数检查、欺诈检查、工作性质检查、额度控制、征信评分、审批流程流转等功能。记录审查日志在审批业务...
  • 本标准明确了网上银行系统的定义,系统进行了简要描述,并从安全技术、安全管理和业务运作三个方面详细阐述了安全规范的具体内容。安全技术规范从客户端安全、专用安全设备安全、网络通信安全和网上银行服务器端...
  • 银行核心系统概念入门简介

    千次阅读 多人点赞 2019-05-10 17:25:49
    一,银行核心系统是什么? 2011-01-03 csdn 银行核心系统是什么 银行核心系统的英文原意CORE Banking, CORE其实不是“核心”的意思这么简单,它的全称是: Centralized Online Real-time Exchange (集中式在线...
  • 首页、个人中心、通知公告管理、用户管理、员工管理、网点信息管理、账户信息管理、账户存款管理、账户取款管理、账户转账管理、在线咨询管理、...产品管理、贷款信息管理、还款信息管理、离职申请管理、系统管理等功能...
  • 银行存取款管理系统设计

    千次阅读 2021-05-24 03:30:40
    题目:银行存取款管理设计功能:能够输入和查询客户存款取款记录。在客户文件中,每个客户是一条记录,包括编号、客户姓名、支取密码、客户地址、客户电话、账户总金额;在存取款文件中,每次存取款是一条记录,包括...
  • 这是《银行信息化丛书》读书笔记2。做企业架构意义很大,架构的治理更重要,因为要让架构发挥作用。企业架构开发、治理内容很多,框架理论体系就要很长的学习周期和实际经验。本篇是作者的实践总结,比较精简的讲解...
  • 中华人民共和国金融行业标准JR/T 0068—2020 网上银行系统信息安全通用规范是2019年10月份推出代替 JR/T 0068—2012,在2020年2月5日开展实施执行,作为一部通用规范合规要求,很有研读意义。 本标准通过收集、...
  • 2012年,工信部和公安部通告了RSA1024算法被破解的风险,为保证金融行业各基础信息系统安全,中国人民银行要求银行对网上银行等信息系统进行国产密码算法改造。2012年,中国人民银行向多家银行发布了《银行业国产...
  • Python——银行管理系统

    万次阅读 多人点赞 2020-04-10 18:47:11
    银行代码源码解析管理员类Admin()Admin代码ATM()类ATM代码人类person()类person代码银行卡类card()card代码main()主函数银行自动提款代码主函数main()代码银行提款机演示 目录上面 先需要分析,有那些类,类有什么...
  • 操作系统 进程调度-银行家算法实验报告

    千次阅读 多人点赞 2020-06-19 09:56:25
    本实验的目的在于让学生独立的使用高级语言编写和调试一个系统动态分配资源的简单模拟程序,了解死锁产生的条件和原因,并采用银行家算法有效地防止死锁的发生,以加深课堂上所讲授的知识的理解。 二、 实验要求 ...
  • 从商户系统到银行系统,其实主要就是商户的支付系统到银行的存管系统。 平台商户的支付系统对接银行的存管系统,有很多接口和模块,下面我们就来看一下有哪几个模块呢? 子商户信息维护 包括子商户开户,销户...
  • 银行应用系统架构,听上去很复杂、很专业的内容,如何下笔想了很久。 不太想写成一个教科书一般的文章,那样写着轻松但是看着累,最关键的语读者来说,不会有太大的收获。其实一个好的传授者,并不是要把知识写的...
  • 简易银行管理系统(C语言)

    千次阅读 多人点赞 2020-11-08 06:12:32
    简易银行管理系统(C语言)
  • 为了实现银行家算法,每一个进程在进入系统时,它必须申明在运行过程中可能需要煤种资源类型的最大单元数目,其数目不能超过系统所拥有的资源总量。当进程请求一组资源的时候,系统必须首先确定是否有足够的资源分配...
  • 操作系统实验二 银行家算法

    千次阅读 2020-06-05 16:11:43
    实验二 银行家算法 一、实验目的 1、了解什么是操作系统安全状态和不安全状态; 2、了解如何避免系统死锁; 3、理解银行家算法是一种最有代表性的避免死锁的算法,掌握其实现原理及实现过程。 二、实验环境 虚拟机...
  • 操作系统知识——银行家算法

    千次阅读 2019-10-07 11:56:47
    银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 137,568
精华内容 55,027
热门标签
关键字:

对银行系统的要求