Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add WITH (lock) clause for MSSQL select with join queries #8507

Merged
merged 3 commits into from Feb 12, 2022

Conversation

icecreamparlor
Copy link
Contributor

@icecreamparlor icecreamparlor commented Jan 5, 2022

Typeorm didn't supported LOCK clause in MSSQL SELECT + JOIN query.

For example, when we write code with typeorm like this

await getConnection()
        .createQueryBuilder()
        .select("order")
        .setLock("dirty_read")
        .from(Order, "order")
        .innerJoinAndSelect("order", "order.OrderItems")
        .where("1=1")
        .getMany()

we would expect the corresponding SQL of this statement is

SELECT      *
FROM        Order O     WITH (NOLOCK)
LEFT JOIN   OrderItems  WITH (NOLOCK)
WHERE       1=1

but typeorm generates SQL like this

SELECT      *
FROM        Order O     WITH (NOLOCK)
LEFT JOIN   OrderItems  
WHERE       1=1

This pull request enables LOCK with SELECT + JOIN sql query.
This pull request will prevent deadlock situations while querying SELECT statements during transactions. (in case of MSSQL Driver)

Closes: #4764

Description of change

Pull-Request Checklist

  • Code is up-to-date with the master branch
  • npm run lint passes with this change
  • npm run test passes with this change
  • This pull request links relevant issues as Fixes #0000
  • There are new or updated unit tests validating the change
  • (N/A) Documentation has been updated to reflect this change
  • The new commits follow conventions explained in CONTRIBUTING.md

@icecreamparlor icecreamparlor force-pushed the add-lock-in-select-join branch 5 times, most recently from 88f10b4 to 4d6d19f Compare January 5, 2022 15:46
typeorm didn't supported LOCK clause in SELECT + JOIN query. For example, we cannot buld SQL such as "SELECT * FROM USER U WITH(NOLOCK) INNER JOIN ORDER WITH(NOLOCK) O ON U.ID=O.UserID". This pull request enables LOCK with SELECT + JOIN sql query.

Closes: typeorm#4764
@icecreamparlor icecreamparlor changed the title fix: add lock clause for MSSQL select, select with join clause fix: add lock clause for MSSQL select with join clause Jan 5, 2022
@icecreamparlor icecreamparlor changed the title fix: add lock clause for MSSQL select with join clause fix: add lock clause for MSSQL select with join queries Jan 5, 2022
@icecreamparlor icecreamparlor changed the title fix: add lock clause for MSSQL select with join queries fix: add WITH (lock) clause for MSSQL select with join queries Jan 6, 2022
@danaryu
Copy link

danaryu commented Jan 9, 2022

Any plans on when to merge this? I think this would solve a lot of my problems!

@pleerock
Copy link
Member

Looks like a breaking change? What is the difference between locks being set on FROM versus on FROM and JOINs?

@icecreamparlor
Copy link
Contributor Author

icecreamparlor commented Jan 15, 2022

I think this pull request only effects on MSSQL Driver.

In summary,

In MSSQL, although we set lock with typeorm entity (or querybuilder), lock mode is partially set in SELECT query. (lock only applies to one table)

In MSSQL, we can set transaction lock mode in SELECT query.

SELECT      *
FROM        Order      WITH (NOLOCK)
WHERE       1=1

When we write SQL like above, we can set NOLOCK mode to SELECT query. We can make such query with typeorm like this.

await getRepository(tbOrder).find({
  where: {
    ...
  },
  lock: {
    // this part
    mode: "dirty_read",
  },
});

But when we write query with typeorm joining other tables like below,

await getRepository(tbOrder).find({
  where: {
    ...
  },
  relations: ["OrderItems"],
  lock: {
    mode: "dirty_read",
  },
});

typeorm generates sql query like this

SELECT      *
FROM        Order O     WITH (NOLOCK)
LEFT JOIN   OrderItems  -- (lock not set in OrderItems!!)
WHERE       ....

In this case, NOLOCK only applies to Order table. NOLOCK not applies to OrderItem table. Which occurs TRANSACTION DEADLOCK in some cases. I faced TRANSACTION DEADLOCK situation like above.

This pull request generates SELECT query like this

SELECT      *
FROM        Order O     WITH (NOLOCK)
LEFT JOIN   OrderItems  WITH (NOLOCK)
WHERE       ...

I changed typeorm code locally, and I found such issue can be resolved by merging this pull request.

Typeorm is one of my favorite library, and I will be very excited if I can contribute to this library.
Have a good weekend : )

@icecreamparlor
Copy link
Contributor Author

icecreamparlor commented Jan 15, 2022

For your question, this link is relevant to answer.

https://stackoverflow.com/questions/3783525/sql-server-nolock-and-joins

@icecreamparlor
Copy link
Contributor Author

Any updates on this pull request ?

@AlexMesser AlexMesser merged commit 3284808 into typeorm:master Feb 12, 2022
@AlexMesser
Copy link
Collaborator

thank you for contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Extend dirty_read and possibly hints in mssql joins
4 participants