Pytanie Łączenie Rails 3.1 z wieloma bazami danych


W ShowNearby przeprowadziliśmy bardzo dużą migrację do RoR 3.1 z PHP i mamy do czynienia z kilkoma problemami, które być może niektóre z was rozwiązały wcześniej.

Mamy duże ilości danych i postanowiliśmy oddzielić naszą DB na kilka baz danych, które możemy obsługiwać oddzielnie. Na przykład nasze konta, miejsca, logi i inne są podzielone na kilka baz danych

Musimy pobrać migracje, mecze, modele, aby grać ładnie, a do tej pory było dość niechlujnie. Niektóre z naszych wymagań dotyczących akceptowalności rozwiązania:

  • jeden model powinien odnosić się do jednej tabeli w jednej z baz danych.
  • rake db: drop - powinien usunąć wszystkie env bazy danych, które określamy w database.yml
  • rake db: create - powinien utworzyć wszystkie env bazy danych, które określimy w database.yml
  • rake db: migrate - powinien uruchamiać migracje do różnych baz danych
  • rake db: test - powinien przechwytywać urządzenia i upuszczać je do różnych baz danych i testować jednostkę / funkcję / etc

Rozważamy ustawienie oddzielnych projektów szyn dla każdej bazy danych i połączenie ich z ActiveResource, ale uważamy, że nie jest to bardzo wydajne. Czy któryś z was wcześniej poradził sobie z podobnym problemem?

Dzięki wielkie!!


76
2018-05-25 09:50


pochodzenie


Rozważamy aktualizację z aplikacji PHP na jedną z szyn; czy miałeś w tym trochę szczęścia? - Tommyixi
Hi @Tommyixi: to było bardzo dawno temu i wiele się zmieniło od tego czasu. Z perspektywy czasu uważam teraz, że jest to lepsze rozwiązanie do agregowania ich w jedną bazę danych niż dzielenie jej na wiele baz danych - Fer Martin


Odpowiedzi:


Aby odpowiedzieć Wukerplank, możesz również umieścić szczegóły połączenia w database.yml jak zwykle pod taką nazwą:

log_database_production:
  adapter: mysql
  host: other_host
  username: logmein
  password: supersecret
  database: logs

Następnie w specjalnym modelu:

class AccessLog < ActiveRecord::Base
  establish_connection "log_database_#{Rails.env}".to_sym
end

Aby zachować te nieczytelne referencje w kodzie aplikacji.

Edytować: Jeśli chcesz ponownie użyć tego połączenia w wielu modelach, powinieneś utworzyć nową klasę abstrakcyjną i dziedziczyć z niej, ponieważ połączenia są ściśle powiązane z klasami (jak wyjaśniono tutaj, tutaj, i tutaj), a dla każdej klasy zostaną utworzone nowe połączenia.

Jeśli tak jest, ustaw rzeczy w następujący sposób:

class LogDatabase < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "log_database_#{Rails.env}".to_sym
end

class AccessLog < LogDatabase
end

class CheckoutLog < LogDatabase
end

141
2018-05-25 15:11



Jak uwzględnić zmianę środowiska? Na przykład w rozwoju chcę establish_connection z log_dev baza danych, ale w produkcji chcę establish_connection z log Baza danych. Czy mogę po prostu zadzwonić? Rails.env ? - Robert Audi
@AzizLight establish_connection "log_database_#{Rails.env}" - Unixmonkey
Bądź uprzedzony. Wygląda na to, że użycie tej metody pozostawia połączenia w dodatkowych bazach danych bez ich ponownego użycia. Spowoduje to zatrzymanie aplikacji pod dużym obciążeniem. - Altonymous
@Altonymous Dobry punkt. Myślę, że odnosisz się do tego zachowania: github.com/rails/rails/issues/7019 Połączenie zostanie połączone z klasą; więc jeśli chcesz ponownie użyć połączenia, powinieneś ustanowić je na klasie abstrakcyjnej i dziedziczyć z niego zamiast AR :: Base. Zaktualizowałem swoją odpowiedź, aby to odzwierciedlić. - Unixmonkey
nic nowego, nie trzeba tego sprawdzać - mrbrdo


Łączenie się z różnymi bazami danych jest dość łatwe:

# model in the "default" database from database.yml
class Person < ActiveRecord::Base

  # ... your stuff here

end

# model in a different database
class Place < ActiveRecord::Base

  establish_connection (
    :adapter  => "mysql",
    :host     => "other_host",
    :username => "username",
    :password => "password",
    :database => "other_db"
  )

end

Byłbym nieufny w tworzeniu wielu projektów Railsowych, ponieważ zwiększysz koszty pobierania danych dla kontrolerów, co może spowolnić proces.

Jeśli chodzi o pytania dotyczące migracji, urządzeń, modeli itp .: Nie sądzę, aby istniała łatwa droga, dlatego proszę pisać osobne pytania i być tak szczegółowe, jak to tylko możliwe.

Konsolidacja DB w jeden nie jest opcją? Ułatwiłoby ci to życie!


18
2018-05-25 10:06



Problem polega na tym, że połączenie z połączeniem nie będzie poprawnie używane z powyższą próbką - Sam Saffron


Znalazłem świetny wpis, który wskaże innym właściwy sposób przeprowadzenia tego sprawdzenia http://blog.bitmelt.com/2008/10/connecting-to-multiple-database-in-ruby.html

Skonfiguruj coś takiego:

database.yml (db config file)

support_development:
    adapter: blah
    database: blah
    username: blah
    password: blah

support_base.rb (plik modelu)

class SupportBase < ActiveRecord::Base
    self.abstract_class = true #important!
    establish_connection("support_development")
end

tst_test.rb (plik modelu)

class TstTest < SupportBase 
    #SupportBase not ActiveRecord is important!

    self.table_name = 'tst_test'

    def self.get_test_name(id)
        if id = nil
            return ''
        else
            query = "select tst_name from tst_test where tst_id = \'#{id}\'"
            tst = connection.select_all(query) #select_all is important!
            return tst[0].fetch('tst_name')
        end
    end
end

PS, to naprawdę nie obejmuje migracji, nie sądzę, że możesz wykonywać migracje na więcej niż jednym DB z rake (chociaż nie jestem pewien, czy jest to trudne "nie można zrobić", to może być możliwe). To był świetny sposób na połączenie i zapytanie o inne bazy danych, których nie kontrolujesz.


11
2017-07-13 23:59





Możesz także dołączyć środowisko Rails, więc twoje bazy testowe i testowe nie są takie same.

establish_connection "legacy_#{Rails.env}"

4
2018-05-16 13:18





The następujący artykuł sugeruje definiowanie nowych zadań Rake w celu osiągnięcia migracji do wielu baz danych. Każde zadanie ustawia własne połączenie, a następnie wykonuje migrację przy użyciu tego połączenia i określonego folderu bazy danych.

Definiuje również znajomego db:migrate który wywołuje dwa inne zadania.

Włączenie tutaj powoduje, że link staje się niedostępny:

desc "Migrate the database through scripts in db/migrate directory."

namespace :db do
  task :migrate do
    Rake::Task["db:migrate_db1"].invoke
    Rake::Task["db:migrate_db2"].invoke
  end

  task :migrate_db1 do
    ActiveRecord::Base.establish_connection DB1_CONF
    ActiveRecord::Migrator.migrate("db/migrate/db1/")
  end

  task :migrate_db2 do
    ActiveRecord::Base.establish_connection DB2_CONF
    ActiveRecord::Migrator.migrate("db/migrate/db2/")
  end
end

Źródło:  Ruby on Rails Połącz się z wieloma bazami danych i migracjami


3
2018-06-17 14:30





Hej, ten post jest stary, ale znalazłem rozwiązanie działające na Rails 3.2, które może pomóc komuś innemu. https://stackoverflow.com/a/16542724/1447654


1
2018-05-14 13:35