Javaweb基礎:配置數據源連接數據庫

JDBC2.0之後提供了使用連接池(connection pooling)和數據源(DataSource)技術訪問數據庫,使用數據源的好處是不用爲每個HTTP請求創建一個連接對象,Servlet建立數據庫連接、執行查詢、處理結果集、請求結束關閉連接。建立連接比較費時,如果每次請求都需要建立連接,將增大請求的響應時間。而數據源事先建立若干連接對象,將之存放在數據庫連接池中供數據訪問組件共享;由數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重複使用一個現有的數據庫連接,並非重新建立一個新的連接,這樣,避免了爲每個HTTP請求建立連接,大大降低請求的響應時間。因此在實際項目應用中常常使用數據源技術訪問數據庫。

數據源是通過javax.sql.DataSource接口對象實現的,可以通過它的getConnection方法獲得數據庫連接,代替了之前JDBC使用DriverManager(驅動管理器類)工具獲得數據庫連接。

一、在項目中配置數據源

Tomcat配置數據源分:局部數據源和全局數據源,區別只是在於是否可被所有的應用程序使用。

1、爲Tomcat添加JDBC驅動程序

JDBC驅動程序能夠爲JAVA程序與數據庫系統建立通信渠道。將下載好的JDBC驅動程序包放置在tomcat根目錄下的lib文件夾下:

本項目數據庫採用mysql,下載鏈接,菜鳥教程中有:https://www.runoob.com/java/java-mysql-connect.html

重啓tomcat,之後在web應用程序根目錄下的META-INF創建配置文件context.xml(一定是context.xml!)

context.xml內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable = "true">
<!-- 
	name:數據源名稱
	type:指定資源類型
	maxActive:同時刻,連接池中活動連接的最大數
	maxIdle:連接池中處於空閒的連接的最大數,處於等待狀態,不會被清除
	username:數據庫用戶名
	password:數據庫密碼
	maxWait:在沒有可用連接時,連接池在拋出異常前等待的最大毫秒數
	driverClassName:使用的JDBC驅動程序的完整類名
	url:傳遞給JDBC驅動程序的數據庫URL
 -->
<Resource 
	name = "myDataSource"
	type = "javax.sql.DataSource"
	maxActive = "10"
	maxIdle = "4"
	username = "myexam"
	maxWait = "5000"
	driverClassName = "com.mysql.jdbc.Driver"
	password = "123456"
	url = "jdbc:mysql://localhost:3306/exam"/>
</Context>

之後需要在web.xml中繼續配置一下

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>MyExam</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
<!--res-ref-name標籤中寫的是數據源名稱-->
  <resource-ref>
    <description>MySQL DBCP</description>
    <res-ref-name>myDataSource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
</web-app>

二、在項目中使用數據源

在項目中使用傳輸對象(通常是JavaBeans)實現對象與數據庫中關係數據的映射(orm,通俗點講就是一張表對應一個類,關鍵字作爲類的私有屬性,,類中提供屬性的get、set方法)。傳輸對象只包含數據元素,不涉及業務邏輯,業務邏輯由業務對象實現(通常就是設計對應的DAO類,裏面實現關於該表某屬性的增刪改查操作,提供方法給servlet進行操作)。傳輸對象通常用於將數據從表示層傳輸到業務層,或者從業務層傳輸到表示層,它必須是可序列化的,即必須實現java.io.Serializable接口。

首先定義一個User類作爲傳輸對象,用於保存或讀取數據。User.java:

package com.myexam.entity;

public class User {
	private String username;
	private String password;
	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;
	}

}

對應數據庫如下:

接下來設計對應UserDao.java進行增刪改查,每次對數據庫進行操作都要連接數據庫,連接數據庫的這段代碼是通用的,我們可以將之抽取出來作爲一個基礎類,之後的其他Dao可通過該基礎類派生出來。所以先設計基礎類BaseDao.java,在BaseDao.java中獲取數據源對象,再通過數據源獲得連接對象。

通過數據源對象獲得數據庫連接對象不能直接通過實例化方法來生成DataSource對象,而是採用Java命名與目錄接口(JNDI)技術獲得DataSource對象的引用。根據課本,可以簡單理解JNDI爲一種將名字和對象綁定的技術,對象工廠負責創建對象,這些對象都和唯一的名字綁定,外部程序可以通過名字來獲得某個對象的訪問。關於JNDI的深入理解可以參考:https://blog.csdn.net/sunkobe2494/article/details/50824359

那麼獲取數據源需要使用JNDI技術,我們可以通過提供名字與對象綁定的上下文對象lookup(name)方法獲得數據源,再通過數據源對象的getConnection()獲得數據庫連接對象Connection。

BaseDao.java:

package com.myexam.dao;

import java.sql.Connection;

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



public class BaseDao {
	DataSource dataSource;
	//在構造方法裏獲得數據源
	public BaseDao(){
		try{
			Context context =  new InitialContext();
			//lookup的參數必須加上java:comp/env前綴+數據源名稱
			dataSource = (DataSource)context.lookup("java:comp/env/myDataSource");
		}catch(NamingException ne){
			System.out.println("NamingException:"+ne);
		}
	}
	//獲得數據庫連接對象
	public Connection getConnection() throws Exception{
		return dataSource.getConnection();
		
	}
	
	

}

如果出現getConnection方法報錯如下,注意DataSource導入包是否是:import javax.sql.DataSource;以及Connection導入的包是否是:import java.sql.Connection;

創建UserDao類,繼承BaseDao類,在UserDao類中可以實現數據庫的增刪改查操作。這就免不了要寫數據庫操作語句,這裏使用的是PreparedStatement不是Statement,它們的區別就是,PreparedStatement是預編譯好了的sql語句,在需要寫入外部傳入的數據的地方,使用佔位符?,當調用該方法傳入外部數據時,數據被填入已經編譯好的sql語句中執行。這樣就當一個sql語句被多次執行時,數據庫就不用每執行一次就編譯一次,做很多重複的操作,有利於提高執行效率。

String sql = "INSERT INTO user"+"(username,password)VALUES(?,?)";

之後對sql語句進行預編譯之後獲得PreparedStatement對象,再將外部數據與佔位符進行綁定

Connection conn = dataSource.getConnection();

//預編譯處理
PreparedStatement pstmt = conn.prepareStatement(sql);

//綁定數據,1代表第一個佔位符
pstmt.setString(1, user.getUsername());

pstmt.setString(2, user.getPassword());

//執行sql語句

pstmt.executeUpdate(); 

UserDao.java:

package com.myexam.dao;

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

import com.myexam.entity.User;


public class UserDao extends BaseDao{
	public boolean addUser(User user) {
		String sql = "INSERT INTO user"+"(username,password)VALUES(?,?)";
		try {
			Connection conn = dataSource.getConnection();
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, user.getUsername());
			pstmt.setString(2, user.getPassword());
			pstmt.executeUpdate();
			pstmt.close();
			conn.close();
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}
	}

}

如果出現Connection的prepareStatement方法報錯如下,注意PreparedStatement導入包是否是:import java.sql.PreparedStatement;

 至此,在用戶進行註冊請求的時候,創建registerServlet類去處理註冊請求,可以在registerServlet類中使用UserDao類中定義的方法將數據插入數據庫

registerServlet.java:

package com.myexam.servlet.register;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.myexam.dao.UserDao;
import com.myexam.entity.User;


/**
 * Servlet implementation class RegisterServlet
 */
@WebServlet("/register.do")
public class RegisterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public RegisterServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		User user = new User();
		UserDao dao = new UserDao();
		//如果用戶名出現亂碼,可能需要在從處用utf-8重新編碼一下,String(str,"utf-8");
		user.setUsername(request.getParameter("username"));
		user.setPassword(request.getParameter("password"));
		boolean success = dao.addUser(user);
		if(success){
			System.out.println("註冊成功");
		}else{
			System.out.println("註冊失敗");
		}
		
	}

}

之後只需要創建個register.jsp頁面進行請求 。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="./css/bootstrap.min.css">
<link rel="stylesheet" href="./css/login.css">
<title>註冊</title>
</head>
<body>
<div class="container-fluid" >
	<div class="row bg"></div>
	<div class="row">
		<div class="col-md-4 col-md-offset-4 form-box">
			<form action="register.do" method="post" class="form-horizontal row form-content" role="form">
				<div class="form-group">
					<label class="col-md-2" for="user">用戶名:</label>
					<div class="col-md-10">
						<input class="form-control" type="text" name="username" id="user" placeholder="用戶名"></input>
					</div>
				</div>
				<div class="form-group">
					<label class="col-md-2" for="pwd">密碼:</label>
					<div class="col-md-10">
						<input class="form-control" type="password" name="password" id="pwd" placeholder="密碼"></input>
					</div>
				</div>
				<div class="form-group">
					<label class="col-md-2" for="pwd">確認:</label>
					<div class="col-md-10">
						<input class="form-control" type="password" name="password" id="pwd" placeholder="密碼"></input>
					</div>
				</div>
				<div class="form-group">
					<button class="btn btn-info col-md-5" type="submit" >註冊</button>
					<button class="btn btn-info col-md-offset-2 col-md-5" type="reset" >重置</button>
				</div>
				
			</form>
			<div class="row">
				<a href="./login" class="pull-right">點擊此處返回登錄</a>
			</div>
		</div>
		
	</div>
	
</div>
</body>
<script type="text/javascript" src="./js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="./js/bootstrap.min.js"></script>
</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章