Ответы пользователя по тегу JDBC
  • Как присоединить Базу данных к своему проекту на GitHub?

    EugeneP2
    @EugeneP2
    Java Dev
    Если БД не большая, то можно использовать встраиваемую (imbedded) базу данных, например H2.

    База будет подыматься вместе с вашим приложением.

    Все что нужно, это подключить в зависимости JDBC драйвер
    <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <version>1.4.192</version>
            </dependency>


    И указать URL с нужными параметрами

    Простой пример
    import java.sql.*;
    
    public class H2Main {
    
        static {
            try {
                Class.forName("org.h2.Driver");
            } catch (ClassNotFoundException e) {
                System.err.println("Error load H2 JDBC driver: " + e.getMessage());
            }
        }
    
    
        public static void main(String[] args) {
    
            try (Connection con = DriverManager.getConnection("jdbc:h2:./h2example", "sa", "")) {
    
                createSimpleDBSchema(con);
    
                System.out.printf("Message from H2: %s\n", getMessage(con));
    
    
            } catch (Exception e) {
                System.err.printf("%s: %s\n", e.getClass().getSimpleName(), e.getMessage());
            }
    
    
        }
    
    
        static void createSimpleDBSchema(Connection con) {
            try (Statement stmt = con.createStatement()) {
    
                stmt.executeUpdate("CREATE TABLE HelloH2 (message varchar(255) NULL);");
    
                stmt.executeUpdate("INSERT INTO HelloH2 (message) VALUES ('Hello World!')");
    
            } catch (SQLException e) {
                System.err.printf("%s: %s\n", e.getClass().getSimpleName(), e.getMessage());
            }
        }
    
    
        static String getMessage(Connection con) throws SQLException {
    
            try (Statement stmt = con.createStatement();
                 ResultSet rs = stmt.executeQuery("SELECT message FROM HelloH2")) {
    
                if (rs.next())
                    return rs.getString("message");
                else
                    return null;
    
            }
        }
    
    }
    Ответ написан
  • Как сделать, чтобы JDBC использовал мой класс для decimal полей?

    EugeneP2
    @EugeneP2
    Java Dev
    Как-то подменить возвращаемый BigDecimal методом ResultSet#getBigDecimal у вас не выйдет, так как это определено jdbc спецификацией.
    Помимо этого, BigDecimal immutable клаcc, и переопределить его не выйдет, даже если ваш класс Curr расширяет Number, вы сможете только привести их общему типу, т.е. к Number. Попытка привести BigDecimal к Curr или на оборот приведет к ClassCastException.

    Проще сделать как написал Виталий Витренко, но можно заморочиться и запроксить Driver, Connection, Statement и ResultSet и после вызова метода gеBigDecimal выполнять нужные преобразования...

    Вот такой вот велосипед :)

    Прокси псевдо драйвер, который сам регистрируется в DriverManager
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.math.BigDecimal;
    import java.sql.*;
    
    public final class PostgresDriverProxyRegister implements InvocationHandler {
    
    	static {
    		try {
    			DriverManager.registerDriver((Driver) newProxy(new org.postgresql.Driver()));
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    
    
    	public static Object newProxy(Object target) {
    		Class<?> clazz = defineInterface(target);
    		return clazz == null ? target
    				: Proxy.newProxyInstance(Driver.class.getClassLoader(), new Class[]{clazz}, new PostgresDriverProxyRegister(target));
    	}
    
    	public static Class<?> defineInterface(Object o) {
    
    		if (o == null)
    			return null;
    
    		if (o instanceof Driver)
    			return Driver.class;
    		if (o instanceof Connection)
    			return Connection.class;
    		if (o instanceof Statement)
    			return Statement.class;
    		if (o instanceof PreparedStatement)
    			return PreparedStatement.class;
    		if (o instanceof ResultSet)
    			return ResultSet.class;
    
    		return null;
    	}
    
    
    	private final Object target;
    
    	private PostgresDriverProxyRegister(Object target) {
    		this.target = target;
    	}
    
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    		String methodName = method.getName();
    
    		// в этом блоки можно делать нужные изменения для возвращаемых значений методамы ResultSet
    		if (proxy instanceof ResultSet) {
    			Object invokeResult = method.invoke(target, args);
    			if (invokeResult != null) {
    				if ("getBigDecimal".equals(methodName)) {
    					// округляем до 2-х знаков после запятой
    					BigDecimal bigDecimal = (BigDecimal) invokeResult;
    					invokeResult = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
    				} else if ("getString".equals(methodName)) {
    					// убираем пробелы в начале и конце строки, делаем строку в верхнем регистре
    					String s = (String) invokeResult;
    					invokeResult = s.trim().toUpperCase();
    				}
    			}
    
    			return invokeResult;
    		}
    
    		if (proxy instanceof Driver) {
    			if ("acceptsURL".equals(methodName) || "connect".equals(methodName)) {
    				// меняем префикс на оригинал
    				String url = (String) args[0];
    				if (url.startsWith("jdbc:postgresql-proxy:")) {
    					args[0] = url.replace("jdbc:postgresql-proxy:", "jdbc:postgresql:");
    				}
    			}
    		}
    
    		return invokeAndProxy(method, args);
    	}
    
    	public Object invokeAndProxy(Method method, Object[] args) throws Throwable {
    		Object returnValue = method.invoke(target, args);
    		return newProxy(returnValue);
    	}
    }


    Для самой программы, работы с jdbc никак не изменится, только нужно изменить префикс url-а к БД

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    
    public class Main {
    
        public static void main(String[] args) throws Exception {
    
            Class.forName("ua.home.jdbc.driver.warp.postgres.PostgresDriverProxyRegister");
    
            try(Connection connection = DriverManager
                    // используем отличный от оригинала прификс к url 'jdbc:postgresql-proxy:', что бы именно наш драйвер грузился
                    .getConnection("jdbc:postgresql-proxy://localhost:5432/test_db", "test_user", "test_password");
                Statement statement = connection.createStatement();
                ResultSet rs = statement.executeQuery("SELECT 12.65456161 as testDecimal, '  tEsTsTrinG    ' as testString")) {
    
                if (rs.next()) {
                    System.out.printf("testDecimal = '%s'\n", rs.getBigDecimal("testDecimal"));
                    System.out.printf("testString = '%s'\n", rs.getString("testString"));
                }
    
                /* output in console
                        testDecimal = '12.65'
                        testString = 'TESTSTRING'
                */
    
            }
        }
    }
    Ответ написан
  • Как экранировать спец символы в строке перед вставкой в запрос?

    EugeneP2
    @EugeneP2
    Java Dev
    Вы наверно формируете запрос вставки конкатенацией строки?

    Используйте PreparedStatement
    Ответ написан
  • Можно ли использовать try с ресурсами для закрытия connection из пула?

    EugeneP2
    @EugeneP2
    Java Dev
    Да, можно. Все что наследует интерфейс AutoCloseable можно использовать в try-with-resources

    Нужно смотреть что это за "connectionPool"... Если это реализация DatSource, например получаемая из томката, или org.apache.commons.dbcp.BasicDataSource... То вызов метода close возвратит коннекшен обратно в пул. А если человек как то напрямую работает с пулом, то тут нужно бить по рукам
    Ответ написан
  • Как узнатьсколько строк вернул запрос?

    EugeneP2
    @EugeneP2
    Java Dev
    Никак не узнать.

    Или перед основным запросом выполнить SELECT count(*) FROM TABLE
    Ответ написан
  • Преобразование BLOB к ArrayList?

    EugeneP2
    @EugeneP2
    Java Dev
    Вот рабочий пример. Одно только условие, класс CabinetSquad должен наследовать Serializable интерфейс.

    List<CabinetSquad> list = new ArrayList<CabinetSquad>(Arrays.asList(
    
    		new CabinetSquad("a", 1), new CabinetSquad("b", 2), new CabinetSquad("c", 3)
    
    		));
    
    		ByteArrayOutputStream bout = new ByteArrayOutputStream();
    
    		ObjectOutputStream ooStream = new ObjectOutputStream(bout);
    		try {
    			ooStream.writeObject(list);
    		} finally {
    			try {
    				ooStream.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    
    		byte[] byteArray = bout.toByteArray();
    
    		// ----------------------------------
    
    		Connection con = dataSource.getConnection();
    		try {
    
    			Statement s = con.createStatement();
    			s.executeUpdate("CREATE TABLE ARRAY_LIST (id int not null primary key, list blob not null)");
    			s.close();
    
    			// -----------------------------
    
    			PreparedStatement p = con.prepareStatement("INSERT INTO ARRAY_LIST VALUES (?,?)");
    			p.setInt(1, 1);
    			p.setBlob(2, new ByteArrayInputStream(byteArray));
    			p.executeUpdate();
    			p.close();
    
    			// ------------------------------------------------
    
    			PreparedStatement p2 = con.prepareStatement("SELECT list FROM ARRAY_LIST WHERE id = ?");
    
    			p2.setInt(1, 1);
    
    			ResultSet rs = p2.executeQuery();
    
    			if (rs.next()) {
    
    				Blob blob = rs.getBlob("list");
    
    				ObjectInputStream objectInputStream = new ObjectInputStream(blob.getBinaryStream());
    				try {
    
    					List<CabinetSquad> recoverList = (List<CabinetSquad>) objectInputStream.readObject();
    
    					for (CabinetSquad sc : recoverList) {
    						System.out.println(sc);
    					}
    
    				} finally {
    					try {
    						objectInputStream.close();
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    				}
    
    			}
    
    			rs.close();
    			p2.close();
    
    		} finally {
    			try {
    				con.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    Ответ написан