LINUX.ORG.RU

Потокобезопасность синглтона для подключений к БД

 , , , ,


0

1

Добрый, вечер. Подскажите пож., это потокобезопасный класс? Используется сервлетом в качестве помощника работы с SQL DB. Интересует ds (DataSource) который должен быть получен только один раз. Есть ли более изящные альтернативы ? Только не enum.

package org.lalala;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

// TODO: log4j.
// TODO: В спецификацию EJB 3.1 добавлена возможность использования аннотации @Singleton.

public class FirebirdHelper {

	private static DataSource ds = null;
	private static boolean dsready = false;

	private FirebirdHelper() {}

	private static class Handler {
		private static FirebirdHelper instance;

		static {
			try {
				instance = new FirebirdHelper();
			} catch (Exception e) {
				System.err.println("Error: Exception in FirebirdHelper constructor.");
			}
		}
	}

	public static FirebirdHelper getInstance() {
		return Handler.instance;
	}

	private static synchronized DataSource getDataSourceHelper() {
		try {
			Context initContext = new InitialContext();
			Context envContext  = (Context) initContext.lookup("java:/comp/env");
			ds = (DataSource) envContext.lookup("jdbc/FB");
			//envContext.close();initContext.close();
		} catch (NamingException e) {
			System.err.println("Error: naming error.");
			dsready = true; // В случае "несоздания" мы не хотим дергать метод бесконечно.
			return null;
		}
		dsready = true;
		return ds;
	}

	private DataSource getDataSource() {
		if (ds == null && dsready == false) {
			ds = getDataSourceHelper();
		}
		return ds;
	}

	private Connection getConnection() {
		Connection c = null;
		DataSource ds = getDataSource();

		if (ds != null) { 
			try {
				c = ds.getConnection();
			} catch (SQLException e) {
				System.err.println("Error: Conection error");
				return null;
			}
		}
		
		return c;
	}


	public boolean addPeople(String name, String mail, String phone, String cash) {

		boolean result = false;
		PreparedStatement stmt = null;
		Connection c = getConnection();

		if (c == null)
			return false;

		try {
			stmt = c.prepareStatement("INSERT INTO people (NAME,MAIL,PHONE,CASH) VALUES (?,?,?,?)");
			stmt.setString(1, name);
			stmt.setString(2, mail);
			stmt.setString(3, phone);
			//stmt.setInt(4, Integer.valueOf(cash));
			stmt.setInt(4,0);
			stmt.executeUpdate();
			result = true;
		} catch (SQLException e) {
			System.err.println("Error: SQL insert error");
			e.printStackTrace();
		}

		try {
			stmt.close();
		} catch (SQLException e) {
			System.err.println("Error: SQL statement close error");
		}

		try {
			c.close();
		} catch (SQLException e) {
			System.err.println("Error: SQL connection close error");
		} // Return connection to pool.

		return result;

	}

}

нет. Один поток может войти в метод private static synchronized DataSource getDataSourceHelper() {, а второй будет ждать на строке ds = getDataSourceHelper();
и после первого тоже зайдет туда же. Проверка ds на налл тоже должна быть внутри синхронайзед блока.

И не по теме: очередной велосипед. Воспользуйтесь любым готовым решением.

JFreeM ★★★☆
()
Ответ на: комментарий от JFreeM

Точно, испаравил, спс. К сожалению не нашел ни одного подходящего велосипеда, можно узнать направление куда копать ?

koi8-r
() автор топика

double-checked locking

Можно сделать volatile ds - тогда синхронизация будет при каждом обращении (а не только внутри synchronized блока).

Еще вариант (из Effective Java):

// Singleton with public final field
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() { ... }
}

Вариант 2:

In the second approach to implementing singletons, the public member is a static factory method:

// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();

    private Elvis() { ... }

    public static Elvis getInstance() { return INSTANCE; }
}

Ну и все-таки:

a single-element enum type is the best way to implement a singleton.

kovrik ★★★★★
()
Ответ на: комментарий от kovrik

Дело в том, что меня больше интересует не создание синглтона, а инициализация ds один раз и желательно не в конструкторе и без volatile ... ну еще потокобезопасность моего бредового кода=) Я в принципе узнал, все, что хотел. Всем огромное спасибо.

koi8-r
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.