пятница, 26 февраля 2010 г.

среда, 10 февраля 2010 г.

Производительность java-программ

Производительность java-программ можно увеличить, если применить серверные настройки (которые не так сильно экономят память, как настройки по умолчанию):
java -server MyApp
Если верить публикациям в интернете, то производительность может иногда увеличиться в два раза.

вторник, 9 февраля 2010 г.

Swing и многопоточность

Для прорисовки интерфейса в Java с помощью библиотеки swing лучше пользоваться, например, SwingUtilities.invokeLater(Runnable r), а не обычно создавать поток и запускать в нем Runnable. В противном случае будут лезть непонятные ошибки типа JTable Exception in thread "AWT-EventQueue-0" (ArrayIndexOutOfBoundsEx...) или подобные. Это происходит потому, что обращаться к swing-компонентам можно только из потока Event Dispatch Thread (EDT). Функцияция invokeLater ставит задачу в очередь на потоке EDT (т.к. все взаимодействие с swing-овскими графическими элементами управления необходимо осуществавлять только в потоке EDT). Но это не работает в случае, если необходимо выполнить длительный процесс, который заставит ждать поток EDT. Для таких случаев необходимо вместо обычного Thread задействовать SwingWorker.
Очень хорошая русскоязычная статья по этой теме:
http://developers.sun.ru/content/view/159/89/
и еще одна статья (видимо, слегка устаревшая):
http://www.ibm.com/developerworks/ru/edu/j-medswing/section4.html

Очень важно понять, что никаких обращений к swing-компонентам внутри метода SwingWorker.doInBackground() быть не должно т.к. он выполняется в отдельном потоке (не EDT) и если обращаться к swing-компонентам не из EDT потока, то это может стать причиной возникновения исключений. Вывод результатов можно производить, например, в методе SwingWorker.done(), который выполняется в потоке EDT и автоматически вызывается после того, как doInBackground() завершит свою работу, что оберегает нас от возможных проблем.

среда, 3 февраля 2010 г.

Процедуры и триггеры в Oracle

Процедуры
Ниже приведен пример кода процедуры. Сампример немного громоздок, т.к. взят непосредственно из рабочей базы без каких-либо модификаций и упрощений:
create or replace procedure jlb_set_kr_by_phone
is
 is_region_found NUMERIC(1,0);
 pers sch2.jlb_pays_temp2.account%TYPE;
 vcode_count NUMERIC(5,0);
 valid_vcode NUMERIC(5,0);
begin
 --перебираем лицевые
 FOR c1 IN (SELECT phone
    FROM sch2.jlb_pays_temp2
    WHERE phone IS NOT NULL AND account IS NULL) LOOP
   
  is_region_found := 0;
  vcode_count := 0;
  --ищем код района лицевого счета
  FOR c2 IN (SELECT
      z.vcode,
      c.npers
     FROM
      BS.BSSUBSACCT SA,
      bs.bstechnic t,
      bs.bstechsubs ts,
      bs.bsclient c,
      bs.vbszone z
     WHERE
      sa.nsubs = c.nclient_id
      and ts.nsubs=sa.nsubs
      and t.ntech_id=ts.ntech
      and t.vcode = c1.phone
      and c.nzone = z.nzone_id) LOOP
   --признак физ. или юр. лица  
   pers := c2.npers;
   --запомним найденный код р-на
   valid_vcode := c2.vcode;  
   --укажем, что код р-на такого лицевого был найден
   is_region_found := 1;
   --считаем кол-во найденных р-нов    
   vcode_count := vcode_count + 1; 
  END LOOP; --end c2

  --если все в порядке
  IF is_region_found = 1 AND vcode_count = 1 AND pers IS NOT NULL THEN
   UPDATE sch2.jlb_pays_temp2 p
   SET p.is_invalid = 0, p.reg_code = valid_vcode
   WHERE p.phone = c1.phone;
  END IF;
  --если не найдено кодов района (т.е. телефон не найден ни в одном из р-нов)
  IF is_region_found = 0 THEN
   UPDATE sch2.jlb_pays_temp2 p
   SET p.is_invalid = 6
   WHERE p.phone = c1.phone;
  END IF;
  --если неск. кодов района - тоже ошибка
  IF is_region_found = 1 AND vcode_count > 1 THEN
   UPDATE sch2.jlb_pays_temp2 p
   SET p.is_invalid = 7
   WHERE p.phone = c1.phone;
  END IF;
  --если это юрлицо
  IF pers IS NULL THEN
   UPDATE sch2.jlb_pays_temp2 p
   SET p.is_invalid = 1
   WHERE p.phone = c1.phone;
  END IF;
 
 END LOOP; --end c1

 commit;

end jlb_set_kr_by_phone;


* This source code was highlighted with Source Code Highlighter.
В вышеприведенном примере, если говорить коротко, в таблице выставляются соостветствующие телефонам коды районов.

Триггеры
Иногда достаточно удобно использовать триггеры. Допустим, у нас есть таблица файлов платежей, у записей которой есть потомки - платежи, хранящиеся в таблице платежей. Необходимо, чтобы при удалении файла автоматически удалялись и все платежи, связанные с ним. Ниже представлен простой пример:
--таблица файлов
create table jlb_files(
 file_id number(10) PRIMARY KEY USING INDEX,
 bank_id number(10),
 file_name varchar2(50),
 file_date DATE,
 upload_date DATE,
 total_pays_cnt NUMERIC(9, 0),
 total_pays_sum NUMERIC(10, 2)
);

--таблица оплат
create table jlb_pays(
 pay_id number(10) PRIMARY KEY USING INDEX,
 file_id number(10),
 account varchar2(20),
 pay_sum NUMERIC(9,2),
 pay_date DATE,
);

--триггер
CREATE OR REPLACE TRIGGER jlb_files_before_delete
BEFORE DELETE
ON jlb_files
FOR EACH ROW
DECLARE
BEGIN
 DELETE FROM jlb_pays p
 WHERE :old.file_id = p.file_id;
END;


* This source code was highlighted with Source Code Highlighter.
Очевидно, что jlb_files - это таблица файлов, а jlb_pays - это таблица дочерних платежей. При удалении файла из jlb_files автоматически удаляются все платежи с соответствующим file_id. В теле триггера видно, что old представляет собой удаляемую строку.
http://www.techonthenet.com/oracle/triggers/before_delete.php