Ukládání sesion dp databáze, je to dobrý nápad?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
zool
Člen | 144
+
0
-

Ahoj chtěl jsem se zeptat, jestli nedělám neco špatně. Mám hosting u active a tam mám omezený počet souborů, ten počet je včetně souborů od session. Dělá mi to problém, protože souborů od session je nějak hodně, nechávám aktivní session po dobu 40 dnů, a tím nahromaděním souborů překročím limit. Proto jsem začal session ukládat do databáze. Nedá se to množství nějak omezit?? Složku používám standartní nikam to nepřeukládám.

Díky

Filip Procházka
Moderator | 4668
+
0
-

Ukládání session do databáze není problém, ale musíš spolehlivě vyřešit zamykání řádků, jinak budeš mít problémy.

zool
Člen | 144
+
0
-

To jsem při vytváření třídy neřešil. A je to potřeba, když přece každů uživatel má jen ten svůj řádek nebo ne? A nevíte jestli má nástroj database ORM v sobě už něco implementováno na zamykání tabulek?

Filip Procházka
Moderator | 4668
+
0
-

Nejprve si najdi nějaké čtení o tom, proč je to potřeba a jak se to dělá.

zool
Člen | 144
+
0
-

A nějaký odkaz by nebyl, já jsem hledal, ale nějak nemůžu najít. Co jsem našel, tak tam o uzamykání tabulky nebylo třeba…Narazil jsem na ten Redis, ale te je pro mě nepoužitelný, když je to na active
Díky

Jinak mám to podobně jako je to tady http://www.devshed.com/…-a-Database/ a tam právě taky nic jako zamykání tabulky neřeší.

Editoval zool (21. 11. 2012 16:28)

Jan Tvrdík
Nette guru | 2595
+
0
-

zool wrote: Jinak mám to podobně jako je to tady http://www.devshed.com/…-a-Database/ a tam právě taky nic jako zamykání tabulky neřeší.

Taky to tam mají špatně.

zool
Člen | 144
+
0
-

A kde to je tedy dobře? A to vzniká, ten problém, když se zadá několika násobný ajax požadavek, který pracuje se session?? Nebo jsou ještě jiné problémy?
Já už to mám právě napsané, a zatím to funguje, ale nemám to na ostrém provozu, když to může dělat problémy. Chtěl bych to právě vyřešit a pak to tady umístit, pro ostatní. Děkuji

Editoval zool (21. 11. 2012 17:20)

Filip Procházka
Moderator | 4668
+
0
-

Když jsem dělal zamykání pro svůj Redis storage, tak jsem dva dny studoval články a cizí zdrojáky a psal si testovací nástroje.

Google > „mysql locking“ – http://dev.mysql.com/…-tables.html

Google > „php mysql session storage locking“ – http://stackoverflow.com/…sion-handler

Jediné co se v tomto tématu týká Nette, tak je, jak tvojí storage implemetovat tento interface. Všechno ostatní je otázka na schopnost googlit, číst a chápat základy relačních databází a PHP.

Až budeš mít konkrétní problém, rád ti poradím, ale googlit to za tebe nebudu.

juzna.cz
Člen | 248
+
0
-

Pokud nezamknes session, tak ti to pri race condition treba pri ajaxu muze prepsat. Nastane to jen obcas, takze je to tezke odladit.

Predstav si ze se ti potkaji 2 requesty, napr uzivatel behem chvile klikne na dva ajaxovy odkazy, a ty probihaji takto:
A: .....Start --------------- Konec .......
B: ...............Start–Konec.............

Oba pracuji se sesion. Request A to nacte, dela nejake zmeny. Pak zacne B, nacte (ale zmeny nevidi), udela svoje zmeny, zapise a zkonci. Pak dobehne A, ktere se trosku zpozdilo, a svoje zmeny zapise. V tuto chvili jsou data, ktere zapsal request B, kompletne ztracena.

A to je jen jeden priklad z mnoha, jak ti to muze race condition zabit, pokud to spravne neosetris.

(Btw ani Nette to nema uplne osetrene a stavalo se mi, ze mi mizely session. Musel jsem Nette Session kompletne vypnout. Zkusil jsem to sepsat …)

Editoval juzna.cz (21. 11. 2012 19:32)

Filip Procházka
Moderator | 4668
+
0
-

Nette neřeší zamykání session, protože to řeší PHP. Nedokážu si představit, jak by to zapnutí Nette\Http\Session bez vlastního storage mohlo rozbít.

zool
Člen | 144
+
0
-

HosipLan napsal(a):

Nette neřeší zamykání session, protože to řeší PHP. Nedokážu si představit, jak by to zapnutí Nette\Http\Session bez vlastního storage mohlo rozbít.

Souhlasím,

No a když použiju transakce na celý životní cyklus té mé třídy, tak to nepujde? Nebo to bude pomalé

HosipLan:

díky za tip už to studuju

To je asi ta chyba http://race.phux.net/…/rc-test.php

Editoval zool (21. 11. 2012 19:28)

Filip Procházka
Moderator | 4668
+
0
-

Transkace řeší jiný problém – aby se ti vykonaly všechny SQLka, které tam nasypeš, nebo žádné. Zamknou ti databázi jenom na samotné vykonání, takže neřeší race conditions. Pokud se pletu, opravte mě někdo :)

zool
Člen | 144
+
0
-

No a při té transakci se tabulka neuzamkne? zkusel jsem pohledat a tady něco o tom je (doufám že odkaz pujde) na staně 142
http://books.google.cz/books?…

mkoubik
Člen | 728
+
0
-

Tobě jde o to, aby jsi měl tabulku (nebo řádek) zamknutou po celou dobu vykonávání php requestu (nebo do chvíle kdy víš že už nebudeš do session zapisovat), ne jen po dobu zpracování konkrétního SQL dotazu.

Editoval mkoubik (21. 11. 2012 20:23)

enumag
Člen | 2118
+
0
-

Pokud transakci začnu před čtením session, ukončím po uložení session a nastavím transaction isolation level tak proč by to nefungovalo?

zool
Člen | 144
+
0
-

enumag napsal(a):

Pokud transakci začnu před čtením session, ukončím po uložení session a nastavím transaction isolation level tak proč by to nefungovalo?

Tak přesně jsem to myslel, začátek transakce ve funkci read a konec ve funkci write.

Filip Procházka
Moderator | 4668
+
0
-

To je absolutně nežádoucí. Když nastane chyba během běhu aplikace, zahodí se úplně všechno? Budete dělat zanořené transakce? To není řešení. Navíc to takhle nefunguje.

Napište si na to pořádné testy a implementujte to. Garantuju vám, že to vůbec nebude dělat to, co potřebujete ;)

zamykání !== transakce

//edit: a mít dvě připojení je nechutné plýtvání ;)

enumag
Člen | 2118
+
0
-

Myslel jsem to tak že bych pro tu session měl samostatné connection, ale asi je to nesmysl.

zool
Člen | 144
+
0
-

Ahoj, stále se mi to nějak nedaří mám tuto třídu,

<?php
class MySessionStorage extends \Nette\Object implements \Nette\Http\ISessionStorage
{
    /** @var \Nette\Database\Connection */
    public $database;

    public function __construct(\Nette\Database\Connection $database)
    {
        $this->database = $database;
    }
    public function open($savePath, $sessionName)
    {
        $id = session_id();
        /** Je zamek? Jestli ano, tak cekej */
        while(!$this->database->query("SELECT IS_FREE_LOCK('session_$id') AS lo")->fetch()->lo);
        /** vztvor zamek pro dane id session */
        $this->database->exec("SELECT GET_LOCK('session_$id', 160)");

        return true;
    }
    public function close()
    {
        $id = session_id();
       /** Uvolni zamek dane session */
        $this->database->exec("SELECT RELEASE_LOCK('session_$id')");
        return true;
    }
    /**\
     * @param $id
     * @return string
     */
    public function read($id)
    {
        $data = $this->database->table('session')->find($id);
        if($data->count('*'))
            $data = $data->fetch()->data;
        else
            $data = "";
        return $data;
    }
    /**
     * @param $id
     * @param $data
     * @return bool
     */
    public function write($id, $data)
    {


        $dat = $this->database->table('session')->find($id);
        $this->database->exec("REPLACE INTO session (id, time, data) VALUES (?, ?, ?)",$id, time(),$data);

        return true;
    }
    /**
     * @param int $id
     * @return bool
     */
    public function remove($id)
    {

        $this->database->table('session')->find($id)->delete();

        return true;
    }
    /**
     * @param int $maxlifetime
     * @return bool
     */
    public function clean($maxlifetime)
    {
        $this->database->table('session')->where("time < ?", ( time() - $maxlifetime ))->delete();
        return true;
    }
}

No a problém je asi v tom, že při otevíraní session to nečekat na uvolnení zámků(i když by mělo), nebo to může být způsobené, že by mi prohlížeč nezobrazoval ajax požadavky postupně?? Jak zajišťuje te to čekání?
Díky

Editoval zool (22. 11. 2012 21:00)

zool
Člen | 144
+
0
-

Tak změna, měl jsem špatně vytvořenou testovací funkci, zdá se že to jede v pořádku…

tatyalien
Člen | 239
+
0
-

Nehodil by jsi ještě strukuturu tabulek? Když už to někdo má vyřešené, proč to dělat znovu :-)

zool
Člen | 144
+
0
-

Určitě, podělím se
v configu
jen část ta důležitá

services:
		database: @nette.database.default
		sessionStorage: MySessionStorage(@database)
		session:
			setup:
				- setStorage(@sessionStorage)

Tabulka

CREATE TABLE IF NOT EXISTS `session` (
  `id` varchar(200) NOT NULL,
  `time` varchar(200) NOT NULL,
  `data` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Je lepší použít typ tabulky InnoDB

tatyalien
Člen | 239
+
0
-

Díky ;)

tatyalien
Člen | 239
+
0
-

Tak jsem se na to teprve teď dostal, data se mě už ukládají do DB v pořádku… jen mám problém s třídou ShoppingCart, která mě ukládá košík do session, v neonu i když jsem to přesunul za nastavenou session, tak uloženej košík se neukládá do dob a po redirectu se košík promázne. Jak mám do této třídy nastavit správnou sessionStorage?

edit: na localhostu mě to funguje, ale když to hodím na server, tak ten nebere v potaz košíkovou session ukládat do DB :(

	services:
		database: @Nette\Database\Connection

		authenticator: Authenticator( @modelUser::getUsers(), '%security.salt%' )

		modelShop: ShopModel( @database )

		sessionStorage: MySessionStorage( @database )
		session:
			setup:
				- setStorage(@sessionStorage)
				- setExpiration(+ 30 day)

		shoppingCart:
			class: ShoppingCart
			arguments: [@session, @modelShop, @user]
class ShoppingCart extends Nette\Object
{
        // ShoppingCart object sessionu
        private $cart;
    	/** @var \models\ShopModel */
        private $model;
    	/** @var Nette\Security\User */
        private $user;

        /**
         * @param Nette\Http\Session $session
         * @param ShopModel $model
         * @param Nette\Security\User $user
         */
        public function __construct(Nette\Http\Session $session, ShopModel $model, Nette\Security\User $user)
        {
                $this->cart = $session->getSection(__CLASS__);
		....
	}
}

Editoval tatyalien (15. 12. 2012 9:03)

zool
Člen | 144
+
0
-

Ahoj zkus expiraci session v configu přesunout do prostoru v nette
asi takto

nette:

		session:
			autoStart: smart
			expiration: +30 days
tatyalien
Člen | 239
+
0
-

Nepomohlo, to jsem už zkoušel. Zatím jsem to na serveru vypl. Na localhostu to funguje… Až budu mít víc času, tak se tím snad prošťourám ;)

tatyalien
Člen | 239
+
0
-

Tak jsem zkoušel i dle: https://github.com/…e/issues/562 viz níže, ale závěr je stejný. Na localhostu vše ok, na serveru se už sice jednou za uherák něco propíše do db, ale pak už to hodnoty neaktualizuje.

Kulich:
Aha, poslal jsem předtím pouze půlku konfiguráku, takže takhle to funguje bez jakéhokoliv patche:

sessionStorage: SessionStorage(@database)
session:
    class: Nette\Http\Session
    setup:
        - setStorage(@sessionStorage)

config.neon:

	nette:
		application:
			errorPresenter: Error

		database:
			dsn: '%database.driver%:host=%database.host%;dbname=%database.dbname%'
			user: %database.user%
			password: %database.password%

		#session:
			#expiration: 14 days


	services:
		authenticator: Authenticator
		routerFactory: RouterFactory
		router: @routerFactory::createRouter
		# Databáze:
		database: @Nette\Database\Connection
		sablonyModel: SablonyModel( @database )
		sessionStorage: MySessionStorage(@database)
		session:
			class: Nette\Http\Session
			setup:
				- setStorage(@sessionStorage)

Presenter:

	public function renderDefault()
	{
	$myCounter = $this->getSession('mySessionContainer');
	$myCounter->a = "Pevná hodnota";
	$myCounter->b = rand(1,100);

	$this->flashMessage($myCounter->a, 'success');
	$this->flashMessage($myCounter->b, 'success');
	}

MySessionStorage ⇒ je od zool