简体   繁体   English

sequelize node.js出现唯一约束错误时如何跳过主键自增

[英]How do I skip the primary key auto increment in sequelize node js when unique constraint error occurs

How do I skip the primary key auto increment in sequelize node.js when unique constraint error occurs When I enter same username twice that was defined as unique into mysql by using of Postman my program is running correct way but the problem is the incremental primary key is still continuing.当发生唯一约束错误时,如何在 sequelize node.js 中跳过主键自动递增当我使用 Postman 输入两次被定义为唯一的相同用户名时,我的程序运行正确,但问题是增量主键仍然是继续。 For example when I insert another different username value the program is jumping at one of the sequential primary key as expected.例如,当我插入另一个不同的用户名值时,程序会按预期跳转到顺序主键之一。 So that, How can I stop the auto increment id as I restricted not to insert duplicate username values in my database因此,我如何停止自动递增 id,因为我限制不在我的数据库中插入重复的用户名值

/* DATABASE CONFIGURATION FILE */
    const { Sequelize, QueryTypes, DataTypes, Op, UniqueConstraintError, ValidationErrorItem } = require(`sequelize`);

    const sequelize = new Sequelize(`tutorialdb`, `root`, ``, {
        host: `localhost`,
        dialect: `mysql`,
        logging: true,
        pool: {
            max: 5,
            min: 0,
            acquire: 30000,
            idle: 10000,
        },
    });

    sequelize
    .authenticate()
    .then(() => {
    console.log(`Connection has been established successfully...`);
    })
    .catch((err) => {
    console.log(`Unable to connect to the database: `, err);
    });

    const db = {};
    db.Sequelize = Sequelize;
    db.sequelize = sequelize;
    db.QueryTypes = QueryTypes;
    db.DataTypes = DataTypes;
    db.Op = Op;
    db.ValidationErrorItem = ValidationErrorItem;
    db.UniqueConstraintError = UniqueConstraintError;

    db.postModel = require(`../models/post.model.jsx`)(sequelize, DataTypes);

    db.sequelize.sync({ force: false, alter: false, match: /tutorialdb$/ }).then(() => {
    console.log(`Tables were synced successfully`);
    });

    module.exports = db;

    /* Model definition File */
    module.exports = (sequelize, DataTypes) => {
    const Post = sequelize.define(
    `post`,
    {
        id: {
            type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
            primaryKey: true,
            autoIncrement: true,
        },
        title: {
            type: DataTypes.STRING(30),
            allowNull: false,
            validate: {
                notEmpty: {
                    args: true,
                    msg: `Title is required`,
                },
                len: {
                    args: [3, 50],
                    msg: `Title must between 3 and 30 characters`,
                },
            },
        },
        text: {
            type: DataTypes.STRING(100),
            allowNull: false,
            validate: {
                notEmpty: {
                    args: true,
                    msg: `Text is required`,
                },
                len: {
                    args: [5, 100],
                    msg: `Text must between 5 and 100 characters`,
                },
            },
        },
        username: {
            type: DataTypes.STRING(20),
            allowNull: false,
            unique: true,
            validate: {
                notEmpty: {
                    args: true,
                    msg: `Username is required`,
                },
                len: {
                    args: [3, 20],
                    msg: `Username must between 3 and 20 characters`,
                },
            },
        },
    },
    {
        timestamps: true,
        paranoid: true,
    }
    );

    Post.beforeCreate(async (post, options) => {
        post.username = post.username.toLowerCase();
    });

    Post.beforeUpdate(async (post, options) => {
        post.username = post.username.toLowerCase();
    });

    return Post;
    };

    /* Controller File */
    const db = require(`../config/db.config.jsx`);
    const postModel = db.postModel;

    const Sequelize = db.Sequelize;
    const sequelize = db.sequelize;
    const QueryTypes = db.QueryTypes;
    const DataTypes = db.DataTypes;
    const Op = db.Op;
    const ValidationErrorItem = db.ValidationErrorItem;
    const UniqueConstraintError = db.UniqueConstraintError;

    /* Create new Post */
    exports.create = async (req, res) => {
        const transactions = await sequelize.transaction();
        try {
            const trim = (noSpace) => {
                return noSpace.replace(/\s/g, ``);
            };
            const post = await postModel.create(
                {
                    title: req.body.title,
                    text: req.body.text,
                    username: trim(req.body.username),
            },
            { transaction: transactions }
        );
        await transactions.commit();
        res.status(200).json(post);
        } catch (err) {
            await transactions.rollback();
            const messages = {};
            let message;
            err.errors.forEach((error) => {
                messages[error.path] = error.message;
                message = messages[error.path];
            });
            res.status(500).json(message);
        }
    };

    /* Find All posts */
    exports.findAll = async (req, res) => {
        const transactions = await sequelize.transaction();
        try {
            const title = req.query.title;
            const text = req.query.text;
            const username = req.query.username;
            let finder = title ? { title: { [Op.like]: `%${title}%` } } : text ? { text: { [Op.like]: `%${text}%` } } : username ? { username: { [Op.like]: `%${username}%` } } : null;
            const posts = await postModel.findAll({
                as: `posts`,
                attributes: [`id`, `title`, `text`, `username`, `createdAt`, `updatedAt`, `deletedAt`],
                transaction: transactions,
                lock: false,
                paranoid: false,
                order: [[`id`, `DESC`]],
                where: finder,
            });
            await transactions.commit();
            res.status(200).json(posts);
        } catch (err) {
            await transactions.rollback();
            res.status(500).json(err.message);
        }
    };

    /* Router File */

    module.exports = (app) => {
        const router = require(`express`).Router();
        const postCtrl = require(`../controllers/post.controller.jsx`);

        router.route(`/post`).post(postCtrl.create).get(postCtrl.findAll);

        app.use(`/api/v1`, router);
    };

    /* MiddleWare Logger File */

    const moment = require(`moment`);

    /* Create Logger */
    const logger = (req, res, next) => {
        console.log(`${req.protocol}://${req.get(`host`)}${req.originalUrl} : ${moment().format()}`);
        next();
    };

    module.exports = logger;

    /* Server File */
    const express = require(`express`);
    const cors = require(`cors`);
    const logger = require(`./src/middleware/logger.jsx`);
    const app = express();

    const corsOptions = {
    origin: `http://localhost:4001`,
    optionsSuccessStatus: 200,
    };

    app
    .use(cors(corsOptions))
    .use(logger)
    .use(express.json())
    .use(express.urlencoded({ extended: false }))
    .get(`/`, (req, res) => res.status(200).send(`Welcome to fullstack tutorial application`));

    require(`./src/routes/routers.jsx`)(app);

    const PORT = process.env.PORT || 4000;
    app.listen(PORT, () => console.log(`Server is running on port ${PORT}...`));

The output result is working well. output 结果运行良好。 But the primary Key auto-increment is still continuing但是primary Key自增还在继续

http://localhost:4000/api/v1/post: 2022-08-28T11:02:47+03:00 Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): START TRANSACTION; http://localhost:4000/api/v1/post: 2022-08-28T11:02:47+03:00 执行 (ac12d76f-d7dc-4040-9692-3d6b853feac9): 开始交易; Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): INSERT INTO posts ( id , title , text , username , createdAt , updatedAt ) VALUES (DEFAULT,?,?,?,?,?);执行(ac12d76f-d7dc-4040-9692-3d6b853feac9):插入postsidtitletextusernamecreatedAtupdatedAt )VALUES(默认,?,?,?,?,?); Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): ROLLBACK;执行(ac12d76f-d7dc-4040-9692-3d6b853feac9):回滚;

I had attempted the following solution and works me perfectly.我尝试了以下解决方案并完美地工作。

/* Create new User */
exports.create = async (req, res) => {
    const trim = (noSpace) => {
        return noSpace.replace(/\s/g, ``);
    };
    const transactions = await sequelize.transaction();
    try {
        const { username, password } = req.body;
        const users = await userModel.findOne({
            where: { username: trim(username) },
            transaction: transactions,
        });

        if (users !== null) {
            await transactions.rollback();
            res.json(`Username ${username} already exist`);
        } else {
            const user = await userModel.create(
                {
                    username: trim(username),
                    password: trim(password),
                },
                {
                    transaction: transactions,
                }
            );
            await transactions.commit();
            res.status(200).json(user);
        }
    } catch (err) {
        await transactions.rollback();
        const messages = {};
        let message;
        err.errors.forEach((error) => {
            messages[error.path] = error.message;
            message = messages[error.path];
        });
        res.status(500).json(message);
    }
};
exports.create = async (req, res) => {
    const transactions = await sequelize.transaction();
    try {
        const trim = (noSpace) => {
            return noSpace.replace(/\s/g, ``);
        };
        const [user, created] = await userModel.findOrCreate({
            where: { username: trim(req.body.username) },
            defaults: { password: trim(req.body.password) },
            transaction: transactions,
        });
        return created ? (await transactions.commit(), res.status(200).json(user)) : user ? (await transactions.rollback(), res.json(`Username already exist`)) : err;
    } catch (err) {
        await transactions.rollback();
        const messages = {};
        let message;
        err.errors.forEach((error) => {
            messages[error.path] = error.message;
            message = messages[error.path];
        });
        res.status(500).json(message);
    }
};

I am not sure about issue's existence in previous versions of sequelize.我不确定以前版本的 sequelize 中是否存在问题。 But this issue does not exist if using Object.findOrCreate() with following mentioned versions.但是,如果将 Object.findOrCreate() 与以下提到的版本一起使用,则不存在此问题。

However this issue does appear if using Object.create() method with unique constraint set for field value and not checking field value existence prior to using Object.create() eg in following code email unique property is set and if user.create() is used for an existing email in db an error is thrown but userid is incremented thus for next successful creation userid is not as expected.但是,如果使用 Object.create() 方法并为字段值设置了唯一约束,并且在使用 Object.create() 之前不检查字段值是否存在,例如在以下代码中设置了 email 唯一属性,并且如果 user.create()用于数据库中现有的 email 会抛出错误,但 userid 会递增,因此对于下一次成功创建,userid 与预期不同。

An alternate solution is using user.findOne() prior to use user.create() but out of the scope of this answer and issue can be avoided using object.findOrCreate() as following另一种解决方案是在使用 user.create() 之前使用 user.findOne() 但在这个答案的 scope 之外,可以使用 object.findOrCreate() 避免问题,如下所示

Versions: "mysql2": "^2.3.3", "sequelize": "^6.28.0"版本:“mysql2”:“^2.3.3”,“sequelize”:“^6.28.0”

To avoid the issue try using following approach为避免此问题,请尝试使用以下方法

const router = require("express").Router();
const { Sequelize, DataTypes, Model } = require("sequelize");
const dotenv = require("dotenv");

dotenv.config();

const sequelize = new Sequelize(
  process.env.MYSQL_DB_NAME,
  process.env.MYSQL_DB_USER,
  process.env.MYSQL_DB_PASS,
  {
    host: process.env.MYSQL_DB_HOST,
    dialect: "mysql",
  }
);

class User extends Model {}

User.init(
  {
    userid: {
      type: DataTypes.INTEGER,
      autoIncrement: true,
      primaryKey: true,
      field: "fUserID",
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
      field: "fEmail",
    },
    password: {
      type: DataTypes.STRING(1024),
      allowNull: false,
      field: "fPassword",
    },
    firstname: {
      type: DataTypes.STRING,
      field: "fFirstName",
    },
    lastname: {
      type: DataTypes.STRING,
      field: "fLastName",
    },
    metadata: {
      type: DataTypes.STRING(2048),
      field: "fMetaData",
    },
    created: {
      type: DataTypes.DATE,
      field: "fCreated",
    },
    updated: {
      type: DataTypes.DATE,
      field: "fUpdated",
    },
  },
  {
    sequelize,
    tableName: "tbl_user",
    timestamps: true,
    id: "userid",
    createdAt: "created",
    updatedAt: "updated",
  }
);

router.post("/register", async (req, res) => {
  try {
    const [user, created] = await User.findOrCreate({
      where: { email: req.body.email },
      defaults: {
        password: req.body.password,
        firstname: req.body.firstname,
        lastname: req.body.lastname,
        metadata: "Any thing",
      },
    });

    if (created === false) return res.status(400).send("email already exist");

    res.send(user.toJSON());
  } catch (ex) {
    res.status(400).send(ex.errors[0].message);
  }
});

module.exports = router;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么违反唯一键约束而不是主键约束时,MySQL中会出现自动增量间隔? - Why are there auto increment gaps in MySQL when violating a unique key constraint, but not a primary key constraint? 如何调和主键,非空值,唯一,自动增量和生成? - How to reconcile Primary Key, Not Null, Unique, Auto Increment and Generated? 为什么INNODB批量插入导致自动增量主键跳过值? - Why do INNODB bulk inserts cause the auto increment primary key to skip values? 如何将自动增量主键附加到同一个表中的另一个字段? - How do i append an auto increment primary key to another field in the same table? 使用“ AS SELECT”时如何设置AUTO_INCREMENT主键 - How to set AUTO_INCREMENT PRIMARY KEY when using 'AS SELECT' 无法将主键/唯一键/自动增量添加到此列 - Unable to add primary key/unique key/auto-increment to this column Laravel Migration:当它不是主要时自动增加密钥 - Laravel Migration: auto increment key when it is not primary 插入时自动增加不是主键的列 - auto increment a column that is not a primary key when inserted 主键自动递增 - Primary key auto increment 尽管我已经有一个 UNIQUE 列,但我应该使用自动增量主键吗? - Should i use an auto-increment primary key although i already have a UNIQUE column?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM