dbix::class
TRANSCRIPT
DBIx::Class
Работаем с базой в стиле Perl
WTF is ORM?
ORM = Объектно-реляционная проекция. Т.е. связка между реляционной БД и объектно-ориентированным кодом
Сравним RDB и OOPООП РСУБД
Объект База данных
Тип название таблицы
Аттрибуты столбцы
Методы :-( нет у нас методов
Зачем нужен ORM?
ORM сохраняет объекты в базу и достаёт их. Именно объекты, а не строки!!!Без него в нашем коде получается смесь двух совершенно разных языков - SQL и Perl.Это тупо неудобно!my $message = $user->messages->find( $message_id );my $message = s("SELECT * FROM mess WHERE id=?",undef,$id"):
DBIx::Class
Почему именно он?Самый популярныйБольшое количество плагиновЕсть связки с Catalyst и HTML::FormFuЯ це люблю™
Импорт структуры базы
DBIx::Class::Schema::LoaderТаблицы => КлассыСтолбцы => АттрибутыКомментарии к таблицам => POD*Foreign-ключи => Связи между классами.
* мой патч в последней версии Schema::Loader-а ;-P
Basics
В DBIx::Class есть две основные сущностиResultSet (=where)Row (=object)
ResultSet - это структура для формирования запроса.
Row - полученная из базы строка.
Начинаем работать
Классы:
My::Schema::UserMy::Schema::MessageMy::Schema::ForumMy::Schema::Reply
Связки превращаются в методы:
$user->messages, $message->replies, $reply->message;
Начинаем работать (строки)
my @rows = $rs->all;$row->id$row->name$row->name( 'Изя' )$row->update$row->delete$row->insert
Отношения
package My::Schema::User;__PACKAGE__->add_columns( qw(id name gender) ); __PACKAGE__->has_many( 'posts' => 'My::Schema::Posts', 'user_id' );__PACKAGE__->belongs_to( gender => 'My::Schema::Genders' );1; ...say $user->gender->name; #male say $user->posts->first->title; # Как размножаются ёжики?$user->add_to_posts( { title => 'RE: Как размножаются ёжики' } );$user->posts->find( $post_id );$user->search_related('posts')->search_related('comments', { order_by => 'date' } );
Запросы
$schema->resultset('User')->find($id)$v = $schema->resultset('Users')->search( { name => 'vasya' } );$v->search( { gender => 'f' } )->count;$user->messages->search( { text => { like => '%yandex%' } } )->delete;
man DBIx::Class::ResultSet
Вкусняшки
Prefetch
Нам нужно сэкономить на запросах
my $posts = $schema->resultset('Posts');foreach my $row ($posts->all) { say $post->forum->moderator->name; }
Всего один запрос
my $posts = $schema->resultset('Posts')->search(undef,{ prefetch => { forum => 'moderator' }}); foreach my $post ( $posts->all ) { say $post->forum->moderator->name; }
Подзапросы
my $rs = $people->young->sexy->girls;$phone_db->search( { user_id => { -in => $rs->as_query} } );
Paging
Самая частая задача!Зачем её делать дважды?$resultset->search( { rows => 50 } );$resultset->page(2); $resultset->pager (Data::Page);
Аггрегативные функции
$posts->get_column('rating')->max; $users->count; $users->get_column('age')->avg;
Inflate, Deflate
Мы получаем тип данных из базы и превращаем его в красивый объект.И наоборот
Например, мы можем прозрачно сохранять перловую структуру в каком-то поле!!man DBIx::Class::InflateColumn
Выходим из резервации
плагины
DBIx::Class::FrozenColumns
Прозрачно сохраняем дополнительные столбцы в одном поле$user->name; #этот столбец у нас лежит в базе$user->has_some_useless_property; # а этого - нет
DBIx::Class::DynamicSubclass
В зависимости от какого-то флагового поля в базе, может создавать объекты других типов.Получаем записи из таблицы Animals, а они сразу bless-ятся в кошечек и собачек.
DBIx::Class::CustomPrefetch*
Упрощение работы с несколькими СУБД. Аналог prefetch, но между базами * Данная информация опубликована на правах рекламы :-)
Отладка и оптимизация
ORM - гавно
( как сказал один дядька с Highload )
Итак,
Убедитесь, что дело в базе
DBI_PROFILE=1 ./my_script.plDBI::Profile: 0.046747s 2.34% (39 calls) comments_test.pl @ 2009-10-16 02:41:41
Если таки в базе
DBIС_TRACE=1 ./my_script.pl DBI_PROFILE=2 ./my_script.pl
Найдите медленные запросы
man DBIx::Class::QueryLog
Тормоза в DBIx::Class
Красная пилюля.Применять по крайней необходимости!
$rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
Масштабирование
= репликация
Включаем репликацию
$schema->storage_type( [ '::DBI::Replicated', {balancer=>'::Random'} ] ); $schema->storage->connect_replicants(
[$dsn1, $user, $pass, \%opts], [$dsn2, $user, $pass, \%opts],[$dsn3, $user, $pass, \%opts],);
Profit!