views:

98

answers:

4

Hi,

I have a MySQL DB where a key (a string) is read from a third pary source. However, these are not always guaranteed unique (they're movie titles). So I need to check for key uniqueness, and if not unique, amend it to make it unique - by adding an incremental count at the end of the key for example.

What's the best pattern to do this? I currently have a table which stores every key received from 3rd party and stores a count, so I do:

INSERT INTO MYTABLE(KEY) VALUES(KEY_VAlUE) ON DUPLICATE KEY UPDATE KEY_COUNT = KEY_COUNT + 1

I am using jdbcTemplate and a keyHolder to retrieve the ID of the new (or updated) row. The problem is I also need to get the count back. I can of course now do a second query (SELECT) to fetch the record with that ID. However the issue here is with concurrency. It is possible (although unlikely), another INSERT with the same third-party key occurs just before I do my SELECT. In this case the count would be incremented a second time and I'll get the wrong count back.

Any ideas?

Thanks Richard.

A: 

If you are allowing the system to create arbitrary unique key values for ANY rows (the ones that are not submitted as unique to start with), then, instead of modifying it to be unique, why not create your own internal surrogate key, using auto-incrementing feature (MySQL has that right?), and store the submitted key as it was submitted in a non-unique column attribute.

use the internal surrogate key for all relational integrity constraints, and only use the submitted key for other non-unique requirements...

Charles Bretana
+1  A: 

The best pattern to do this is not to. Keying your table by a string like this, especially where you know ahead of time that there will be collisions, will cause you nothing but grief in the long run. Just use an otherwise-meaningless autoincrement key. You can still index by title if you want, and you don't have to munge your data.

Incidentally, I think that when it comes to movie title collisions, the convention is to append the year of the movie in parentheses, e.g. "The Producers (1968)" versus "The Producers (2005)"

Thom Smith
Hi Thom. Yes I know is not ideal. The reason I want to do it is so that I have nice human-readable url - the title is converted to an URL like so: http://mysite.com/The_Producers. "The_Producers" is thus my unique DB key, which is used to extrcat the correct movie info from the DB. I like the suggestion re the year tho, thanks.
What does your URL have to do with your primary key? There's no reason that they must be connected.
Thom Smith
A: 

Transactions. You are using InnoDB, right? You should be.

However, a movie title sounds like a poor primary key to me. Have you considered adding a synthetic primary key, such as an autoincrement integer?

bobince
Hi bobince. Yes I am using InnoDB. Transactionality is probably what I'll go for. I would use something other than the title as the key, but I want URLs like: http://mysite.com/my_movie_title, so "my_movie_title" is necessarily the key. Cheers for suggestion.
A title can be a unique key without it having to be *the* primary key. In any case, that URL style is nice-looking, but if you ever have to change/correct a movie title all your old references and URLs will break. If dupe movie titles are common (and in a big enough database they probably will be), you'll end up with ‘my_movie_title-12’ anyway, at which point going with the ID-and-slug style mysite.com/1234/my_movie_title doesn't seem like so much of a disadvantage.
bobince
yeah I think you might be right. prob easiest to encode a guaranteed unique key/id in with the title.
A: 

I don't know if there's a "pattern" to do this, but why not simply use a transaction?

START TRANSACTION;

INSERT INTO MYTABLE(KEY) VALUES(KEY_VAlUE) ON DUPLICATE KEY UPDATE KEY_COUNT = KEY_COUNT + 1;
SELECT KEY_COUNT FROM MYTABLE WHERE KEY=KEY_VALUE;

COMMIT;
zombat
Hi Zombat. Thanks for your suggestion, I think this is the best way to do it. Cheers.