Java连接数据库 #01# JDBC单线程适用

官方教程(包括 javase的基础部分):JDBC Basics

重新梳理、学习一下“Java连接数据库”相关的内容。

因为最开始没有认真学多线程和JDBC,一直在自己写的多线程程序中维持下面的错误写法:

  1. 多个线程共用一个connection
  2. connection只开不关

为什么上述做法是错误的呢? 可以参看这个帖子。- - “JDBC规范并未规定那三个对象必须是线程安全的,因此所有的JDBC厂商也不会去弄成线程安全的,正因为如此,所以就会有并发问题。” 、-- “ 并不是说不能把连接对象弄成成员变量,只是不能将其弄成成员变量后,在多线程环境下处于共享这些对象,如果同步处理得不好,那就会产生严重的连接泄漏。为了避免这种情况发生,仅在用时获取连接,用完后马上关掉。” -- “如果你对JDBC、多线程编程没有达到非常熟练的程度,还是老老实实地使用经典的JDBC代码结构。” -- 摘抄自csdn 火龙果被占用了

另外,connection只开不关很容易导致连接失效(mysql默认保持连接的时间是8小时,如果这个连接在8小时内无人访问的话,就会关闭这个连接。- -摘)

我把这些错误代码放在第一小节记录下来,作为java连接数据库的最原始版本,在这之后逐渐改良成可以适应各种场景的正确代码。

代码索引:

  • DDL.sql
  • Profile.java
  • ConnectionFactory.java
  • db-config.properties
  • ProfileDAO.java
  • ProfileDAOImpl.java
  • ProfileDAOTest.java

① DDL.sql

DROP TABLE IF EXISTS `profile`;
CREATE TABLE `profile` (
    `profileId` BIGINT(20) NOT NULL AUTO_INCREMENT,
    `username` VARCHAR(50) NOT NULL,
    `password` VARCHAR(50) NOT NULL,
    `nickname` VARCHAR(50) NOT NULL,
    `last_online` TIMESTAMP NULL DEFAULT NULL,
    `gender` CHAR(1) NULL DEFAULT NULL,
    `birthday` TIMESTAMP NULL DEFAULT NULL,
    `location` VARCHAR(50) NULL DEFAULT NULL,
    `joined` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`profileId`),
    UNIQUE INDEX `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8;

profile表可以基本等价为user表来理解。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

② 对应的实体类Profile.java

package org.sample.entity;

import java.sql.Timestamp;

public class Profile {
    private Long profileId;
    private String username;
    private String password;
    private String nickname;
    private Timestamp last_online;
    private Character gender;
    private Timestamp birthday;
    private String location;
    private Timestamp joined;

    public Profile() {
    }

    public Long getProfileId() {
        return profileId;
    }

    public void setProfileId(Long profileId) {
        this.profileId = profileId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public Timestamp getLast_online() {
        return last_online;
    }

    public void setLast_online(Timestamp last_online) {
        this.last_online = last_online;
    }

    public Character getGender() {
        return gender;
    }

    public void setGender(Character gender) {
        this.gender = gender;
    }

    public Timestamp getBirthday() {
        return birthday;
    }

    public void setBirthday(Timestamp birthday) {
        this.birthday = birthday;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public Timestamp getJoined() {
        return joined;
    }

    public void setJoined(Timestamp joined) {
        this.joined = joined;
    }

    @Override
    public String toString() {
        return "Profile{" +
                "profileId=" + profileId +
                ", username=‘" + username + ‘\‘‘ +
                ", password=‘" + password + ‘\‘‘ +
                ", nickname=‘" + nickname + ‘\‘‘ +
                ", last_online=" + last_online +
                ", gender=" + gender +
                ", birthday=" + birthday +
                ", location=‘" + location + ‘\‘‘ +
                ", joined=" + joined +
                ‘}‘;
    }
}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

③ ConnectionFactory.java或者常说的Dbutil(错误代码 ↓

package org.sample.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ResourceBundle;

/**
 * 单线程适用,只开不关,反复用一个 Connection
 */
public class StaticConnectionFactory {

    private static ResourceBundle rb = ResourceBundle.getBundle("org.sample.db.db-config");

    private static final String JDBC_URL = rb.getString("jdbc.url");

    private static final String JDBC_USER = rb.getString("jdbc.username");

    private static final String JDBC_PASSWORD = rb.getString("jdbc.password");

    private static Connection conn = null;

    static {
        try {
            // Class.forName("org.gjt.mm.mysql.Driver");
            // JDBC 4.0 之后(包括 JDBC 4.0)不再需要 class.forName ,详细查看 javaSE6 之后的 API
            conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
        } catch (SQLException e) {
            throw new RuntimeException("Error connecting to the database", e);
        }
    }

    public static Connection getConnection() {
        return conn;
    }

    public static void setAutoCommit(boolean autoCommit) throws SQLException {
        conn.setAutoCommit(autoCommit);
    }

    public static void commit() throws SQLException {
        conn.commit();
    }

    public static void rollback() throws SQLException {
        conn.rollback();
    }
}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

④ org/sample/db/db-config.properties

jdbc.url=jdbc:mysql://***.**.**.**:3306/profiles?characterEncoding=utf8
jdbc.username=root
jdbc.password=aaaaaaaaaaa

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

⑤ ProfileDAO.java

package org.sample.dao;

import org.sample.entity.Profile;

import java.util.List;

public interface ProfileDAO {

    int saveProfile(Profile profile);

    List<Profile> listProfileByNickname(String nickname);

    Profile getProfileByUsername(String username);

    int updateProfileById(Profile profile);

    int updatePassword(String username, String password);

    int updateLastOnline(String username);
}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

⑥ ProfileDAOImpl.java(为了用“带资源的try”严重画蛇添足了。)

package org.sample.dao.impl;

import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
import org.sample.dao.ProfileDAO;
import org.sample.db.StaticConnectionFactory;
import org.sample.entity.Profile;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

// NotThreadSafe
public class ProfileDAOImpl implements ProfileDAO {

    private static final Connection conn = StaticConnectionFactory.getConnection();

    @Override
    public int saveProfile(Profile profile) {
        int i = 0;
        try (
                PreparedStatement ps =
                        createPreparedStatementForSaveProfile(conn, profile);
        ) {
            i = ps.executeUpdate();
        } catch (SQLException e) {
            if (!(e instanceof MySQLIntegrityConstraintViolationException)) {
                e.printStackTrace();
            }
        }
        return i;
    }

    @Override
    public List<Profile> listProfileByNickname(String nickname) {
        List<Profile> profiles = new ArrayList<>();
        try (
                PreparedStatement ps =
                        createPreparedStatementForListProfileByNickname(conn, nickname);
                ResultSet rs = ps.executeQuery();
        ) {
            while (rs.next()) {
                Profile profile = extractProfileFromResultSet(rs);
                profiles.add(profile);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return profiles;
    }

    @Override
    public Profile getProfileByUsername(String username) {
        Profile profile = null;
        try (
                PreparedStatement ps =
                        createPreparedStatementForGetProfileByUsername(conn, username);
                ResultSet rs = ps.executeQuery();
        ) {
            if (rs.next()) {
                profile = extractProfileFromResultSet(rs);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return profile;
    }

    @Override
    public int updateProfileById(Profile profile) {
        int i = 0;
        try (
                PreparedStatement ps =
                        createPreparedStatementForUpdateProfileById(conn, profile);
        ) {
            i = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return i;
    }

    @Override
    public int updatePassword(String username, String password) {
        int i = 0;
        try (
                PreparedStatement ps =
                        createPreparedStatementForUpdatePassword(username, password);
        ) {
            i = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return i;
    }

    @Override
    public int updateLastOnline(String username) {
        int i = 0;
        try (
                PreparedStatement ps =
                        createPreparedStatementForUpdateLastOnline(username);
        ) {
            i = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return i;
    }

    private Profile extractProfileFromResultSet(ResultSet rs) throws SQLException {
        Profile profile = new Profile();
        profile.setBirthday(rs.getTimestamp("birthday"));
        profile.setJoined(rs.getTimestamp("joined"));
        profile.setLast_online(rs.getTimestamp("last_online"));
        profile.setLocation(rs.getString("location"));
        profile.setNickname(rs.getString("nickname"));
        profile.setPassword(rs.getString("password"));
        profile.setProfileId(rs.getLong("profile_id"));
        profile.setUsername(rs.getString("username"));
        if (rs.getString("gender") != null) {
            profile.setGender(rs.getString("gender").charAt(0));
        }
        return profile;
    }

    private PreparedStatement createPreparedStatementForSaveProfile(Connection conn, Profile profile) throws SQLException {
        String sql = "INSERT INTO `profiles`.`profile` (`username`, `password`, `nickname`) " +
                "VALUES (?, ?, ?)";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, profile.getUsername());
        ps.setString(2, profile.getPassword());
        ps.setString(3, profile.getNickname());
        return ps;
    }

    private PreparedStatement createPreparedStatementForListProfileByNickname(Connection conn, String nickname) throws SQLException {
        String sql = "SELECT  `profile_id`,  `username`,  `password`,  `nickname`,  `last_online`,  `gender`,  `birthday`,  `location`,  `joined`" +
                "FROM `profiles`.`profile`" +
                "WHERE `nickname`=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, nickname);
        return ps;
    }

    private PreparedStatement createPreparedStatementForGetProfileByUsername(Connection conn, String username) throws SQLException {
        String sql = "SELECT  `profile_id`,  `username`,  `password`,  `nickname`,  `last_online`,  `gender`,  `birthday`,  `location`,  `joined`" +
                "FROM `profiles`.`profile`" +
                "WHERE `username`=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, username);
        return ps;
    }

    private PreparedStatement createPreparedStatementForUpdateProfileById(Connection conn, Profile profile) throws SQLException {
        String sql = "UPDATE `profiles`.`profile`" +
                "SET `nickname`=?,  `gender`=?,  `birthday`=?,  `location`=? " +
                "WHERE  `profile_id`=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, profile.getNickname());
        ps.setString(2, profile.getGender() != null ? String.valueOf(profile.getGender()) : null);
        ps.setTimestamp(3, profile.getBirthday());
        ps.setString(4, profile.getLocation());
        ps.setLong(5, profile.getProfileId());
        return ps;
    }

    private PreparedStatement createPreparedStatementForUpdatePassword(String username, String password) throws SQLException {
        String sql = "UPDATE `profiles`.`profile`" +
                "SET `password`=? " +
                "WHERE  `username`=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, password);
        ps.setString(2, username);
        return ps;
    }

    private PreparedStatement createPreparedStatementForUpdateLastOnline(String username) throws SQLException {
        String sql = "UPDATE `profiles`.`profile`" +
                "SET `last_online`=CURRENT_TIMESTAMP " +
                "WHERE  `username`=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, username);
        return ps;
    }
}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

⑦ ProfileDAOTest.java

package org.sample.dao;

import org.junit.Test;
import org.sample.dao.impl.ProfileDAOImpl;
import org.sample.db.StaticConnectionFactory;
import org.sample.entity.Profile;

import java.sql.SQLException;
import java.util.List;

import static org.junit.Assert.*;

public class ProfileDAOTest {

    private ProfileDAO profileDAO = new ProfileDAOImpl();

    private static final String USER_NAME = "hello123";

    @Test
    public void saveProfile() {
        Profile profile = new Profile();
        profile.setUsername(USER_NAME);
        profile.setPassword("231231232");
        profile.setNickname("jack");
        int i = profileDAO.saveProfile(profile);
        System.out.println(i);
    }

    @Test
    public void listProfileByNickname() {
        List<Profile> profiles = profileDAO.listProfileByNickname("123");
    }

    @Test
    public void getProfileByUsername() {
        Profile existProfile = profileDAO.getProfileByUsername(USER_NAME);
        Profile notExistProfile = profileDAO.getProfileByUsername(USER_NAME + "321");
        assertNotNull(existProfile);
        assertNull(notExistProfile);
    }

    @Test
    public void updateProfileById() {
        Profile profile = profileDAO.getProfileByUsername(USER_NAME);
        int i = profileDAO.updateProfileById(profile);
        assertEquals(1, i); // 即便没改变值,但是还是会重新set一遍,因此影响行数还是一行

        profile.setGender(‘f‘);
        profile.setNickname("www" + Math.random());
        int j = profileDAO.updateProfileById(profile);
        assertEquals(1, j);
    }

    @Test
    public void updatePassword() {
        profileDAO.updatePassword(USER_NAME, "www" + Math.random());
    }

    @Test
    public void updateLastOnline() throws SQLException {
        try {
            StaticConnectionFactory.setAutoCommit(false);
            profileDAO.getProfileByUsername(USER_NAME);
            profileDAO.updateLastOnline(USER_NAME);
            StaticConnectionFactory.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                StaticConnectionFactory.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            StaticConnectionFactory.setAutoCommit(true);
        }
    }
}

原文地址:https://www.cnblogs.com/xkxf/p/9354968.html

时间: 2024-11-06 20:53:45

Java连接数据库 #01# JDBC单线程适用的相关文章

Java连接数据库 #02# JDBC经典套路

内容索引 LocalConnectionFactory.java LocalConnectionProxy.java ProfileDAO.java-2.0 ProfileDAOImpl.java-2.0 DaoException.java DbUtil.java-2.0 ProfileDAOTest.java-2.0 DaoTest.java(并发测试) 接Java连接数据库 #01# JDBC单线程适用,主要是改为多线程适用,顺便对DAO层结构进行改良: connection由共享变量改为由

java连接数据库时jdbc设置编码

发现网上很多坑爹货,有很多意思表达不全,比如jdbc连接mysql数据库的时候,设置字符集编码 可以如下配置,mysql可直接在url后面加上字符集设置: ...省略 String url = "jdbc:mysql://localhost:3306/exceltest1?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull"; String username = "

完整java开发中JDBC连接数据库代码和步骤

完整java开发中JDBC连接数据库代码和步骤 JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lang.Class类的静态方法forName(String  className)实现. 例如: try{ //加载MySql的驱动类 Class.forName("com.mysql.jdbc.Driver") ; }catch(Class

java中使用JDBC连接数据库的步骤

java中使用JDBC连接数据库的步骤? 采纳率:46%6级2015.06.30 1.注册驱动Class.forname("com.mysql.jdbc.Driver");//这是连接mysql数据库的驱动2.获取数据库连接java.sql.Connection conn=java.sql.DriverManager.getConnection(); 3.获取表达式java.sql.Statement stmt=conn.createStatement("jdbc:mysql

Java学习资料-Java开发中JDBC连接数据库代码和步骤

完整java开发中JDBC连接数据库代码和步骤:http://www.cnblogs.com/hongten/archive/2011/03/29/1998311.html

Java连接数据库jdbc

java连接数据库 import java.sql.*;public class Jdbc05 { static final String URL="jdbc:mysql://localhost:3306/test"; static final String USER="root"; static final String PWD="root"; public static void main(String[] args) { //定义sql语句

Java学习:JDBC

jdbc简介 DBC(Java Database Connectivity)是一个独立于特定数据库管理系统.通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,使用这个类库可以以一种标准的方法.方便地访问数据库资源. jdbc的核心API Driver接口:数据库驱动程序的接口,所有的数据库厂商需要的驱动程序需要实现此接口. Connection接口:与具体的数据库连接对象: Statement createStatement()    创建一个静态sq

java连接数据库

在软件开发的过程中,和数据库打交道是必须的.java连接数据库比较简单,但是对于刚开始学习编程的人员来说,可能会有点不知从哪里入手,现在就为大家讲解一下java连接数据库的方法: 1.打开myeclipse,新建一个java工程: 在工程下面新建一个包: 2.新建一个java类,叫DBManger,并在此类中编写代码: 代码书写好之后,要加入数据库的驱动包: 右键点击项目----Build path----Configure Build Path---点击Libraries 点击 Add Ext

JAVA数据库编程(JDBC技术)-入门笔记

本菜鸟才介入Java,我现在不急着去看那些基本的语法或者一些Java里面的版本的特征或者是一些晋级的知识,因为有一点.Net的OOP编程思想,所以对于Java的这些语法以及什么的在用到的时候在去发现学习一下.我现在很迫不及待用JAVA想来实现以下对数据库的增删改查.想实现就来看Java是怎么操作数据库的,回想下.Net里你可能会配置web.Config,或者你去写一些DBhelper类然后调用里面的自己定义的一些增删改查的方法,更或者你去配一些数据控件等等往往发现操作基本都是一体化的简单.现在面