我正在使用rails处理标记的博客系统。现在它使用连接表,但我对性能有一些疑问。
现在,每次创建博客及其关联标记时,它都会向每个语句提交数据库。我认为更好的做法应该修补所有这些语句并仅提交数据库一次。在轨道上可以吗?
创建日志转储:
Started POST "/articles" for 127.0.0.1 at 2014-08-29 15:30:48 -0400
Processing by ArticlesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"K4rWQEh0810X2jMe/Z9pC/PN2WeOcO0F0TkjKUZTPec=", "title"=>"test27", "text"=>"ddddd", "tag"=>"a,k,g", "commit"=>"Submit"}
Unpermitted parameters: utf8, authenticity_token, tag, commit
(0.9ms) BEGIN
SQL (0.3ms) INSERT INTO `articles` (`created_at`, `text`, `title`, `updated_at`) VALUES ('2014-08-29 19:30:48', 'ddddd', 'test27', '2014-08-29 19:30:48')
(0.2ms) COMMIT
Tag Load (0.3ms) SELECT `tags`.* FROM `tags` WHERE `tags`.`name` = 'a' LIMIT 1
(0.2ms) BEGIN
SQL (0.3ms) INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 1)
(0.2ms) COMMIT
Tag Load (0.2ms) SELECT `tags`.* FROM `tags` WHERE `tags`.`name` = 'k' LIMIT 1
(0.1ms) BEGIN
SQL (0.2ms) INSERT INTO `tags` (`name`) VALUES ('k')
(0.1ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 17)
(8.3ms) COMMIT
Tag Load (0.3ms) SELECT `tags`.* FROM `tags` WHERE `tags`.`name` = 'g' LIMIT 1
(0.1ms) BEGIN
SQL (0.2ms) INSERT INTO `tags` (`name`) VALUES ('g')
(0.1ms) COMMIT
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 18)
(0.2ms) COMMIT
模型设计:
class Article < ActiveRecord::Base
has_and_belongs_to_many :tag
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :article, :uniq => true
end
博客创建代码:
def create
@article = Article.new(article_params)
tag_arr = params[:tag].split(',')
if @article.save
tag_arr.each do |name|
tag = Tag.find_or_create_by(name: name) # create a new tag only if tag.name not exist
@article.tag << tag
end
redirect_to @article
else
render 'new'
end
end
答案 0 :(得分:1)
要在单个事务中保存文章和标记,请将操作包装在transaction
块中。
def create
@article = Article.new(article_params)
tag_arr = params[:tag].split(',')
Article.transaction do
if @article.save
tag_arr.each do |name|
article.tags.find_or_create_by(name: name)
end
end
end
if @article.new_record?
render 'new'
else
redirect_to @article
end
end
这将导致SQL查询类似于:
(0.9ms) BEGIN
SQL (0.3ms) INSERT INTO `articles` (`created_at`, `text`, `title`, `updated_at`) VALUES ('2014-08-29 19:30:48', 'ddddd', 'test27', '2014-08-29 19:30:48')
Tag Load (0.3ms) SELECT `tags`.* FROM `tags` WHERE `tags`.`name` = 'a' LIMIT 1
SQL (0.3ms) INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 1)
Tag Load (0.2ms) SELECT `tags`.* FROM `tags` WHERE `tags`.`name` = 'k' LIMIT 1
SQL (0.2ms) INSERT INTO `tags` (`name`) VALUES ('k')
SQL (0.3ms) INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 17)
Tag Load (0.3ms) SELECT `tags`.* FROM `tags` WHERE `tags`.`name` = 'g' LIMIT 1
SQL (0.2ms) INSERT INTO `tags` (`name`) VALUES ('g')
SQL (0.4ms) INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES (28, 18)
(0.2ms) COMMIT