使用 Derby & Apache Tomcat
原文: http://zetcode.com/db/apachederbytutorial/tomcat/
在本章中,我们将展示如何将 Derby 与 Apache Tomcat Web 容器组合在一起。
Apache Tomcat 是 Java 编程语言的 Web 容器。 它用于服务 JSP 页面和 servlet。 可以轻松地将 Apache Tomcat 与 Derby 一起使用。 Derby 在其lib
子目录中有一个derby.war
文件。 该 Web 存档仅用于控制 Derby 数据库。 Tomcat 和 Derby 都是 Apache Software Foundation 的项目。
$ pwd
/home/janbodnar/bin/tomcat
$ ls lib/derby*
lib/derbyclient.jar lib/derby.jar lib/derbynet.jar
首先,我们必须将derbyclient.jar
,derby.jar
和derbynet.jar
文件复制到 Tomcat 安装目录的lib
子目录中。
$ ls webapps
derby.war docs examples host-manager manager ROOT
然后,我们必须将 derby.war 文件复制到 Tomcat 安装目录的webapps
子目录文件中。 Tomcat 启动时,将解压缩并部署文件。
$ export JAVA_OPTS=-Dderby.system.home=/home/janbodnar/programming/derby/dbs
当我们通过 Tomcat 启动 Derby 时,不考虑DERBY_OPTS
变量。 在启动 Tomcat 和 Derby 服务器之前,必须先设置derby.system.home
。 我们可以在JAVA_OPTS
变量中设置 Derby 系统目录。
$ bin/startup.sh
Using CATALINA_BASE: /home/janbodnar/bin/tomcat
Using CATALINA_HOME: /home/janbodnar/bin/tomcat
Using CATALINA_TMPDIR: /home/janbodnar/bin/tomcat/temp
Using JRE_HOME: /home/janbodnar/bin/jdk1.6.0_30
Using CLASSPATH: /home/janbodnar/bin/tomcat/bin/bootstrap.jar:
/home/janbodnar/bin/tomcat/bin/tomcat-juli.jar
使用startup.sh
脚本启动 Tomcat 服务器。
图:Tomcat 启动页面
导航到localhost:8080
,这是 Tomcat 监听的默认 URL,我们会看到 Tomcat 欢迎页面。
图:Derby 启动
要启动 Derby 数据库,我们导航到localhost:8080/derby/derbynet
。 这将启动 Derby。 我们有几个按钮可用于启动/停止服务器,启用/禁用日志记录或跟踪。
<load-on-startup>0</load-on-startup>
每次启动 Tomcat 服务器时,我们都必须导航至上述 URL。 要自动启动 Derby,我们可以在web.xml
文件的<servlet>
标记内添加以上行。 该文件位于webapps/derby/WEB-INF
目录中。
创建测试数据库
对于那些从一开始就没有遵循教程的人,我们将再次创建testdb
数据库。 我们将一个表添加到数据库中。 您可以跳过数据库和表(如果已经存在)的创建。
$ cat cars.sql
CREATE SCHEMA USER12;
CREATE TABLE CARS(ID INT PRIMARY KEY, NAME VARCHAR(30), PRICE INT);
INSERT INTO CARS VALUES(1, 'Audi', 52642);
INSERT INTO CARS VALUES(2, 'Mercedes', 57127);
INSERT INTO CARS VALUES(3, 'Skoda', 9000);
INSERT INTO CARS VALUES(4, 'Volvo', 29000);
INSERT INTO CARS VALUES(5, 'Bentley', 350000);
INSERT INTO CARS VALUES(6, 'Citroen', 21000);
INSERT INTO CARS VALUES(7, 'Hummer', 41400);
INSERT INTO CARS VALUES(8, 'Volkswagen', 21600);
我们将需要此 SQL 文件。
$ cat dbs/derby.properties
derby.stream.error.logSeverityLevel=0
derby.database.fullAccessUsers=user12
derby.database.defaultConnectionMode=readOnlyAccess
derby.connection.requireAuthentication=true
derby.user.user12=34klq*
derby.user.user13=33kl33
derby.user.user14=14kl14
derby.user.user15=35rr++
derby.authentication.provider=builtin
在 Derby 系统目录中,我们有derby.properties
文件。 在此文件中,我们配置一些选项。 我们将日志严重性级别设置为 0 以报告所有可能的问题。 这是在测试环境中完成的。 我们启用身份验证。 我们使用相应的密码创建四个用户。 用户 12 中只有一个拥有完全访问权限。 其他人只有readOnlyAccess
。
$ java -Dderby.system.home=/home/janbodnar/programming/derby/dbs \
-Dij.protocol=jdbc:derby: -jar $DERBY_HOME/lib/derbyrun.jar ij
ij version 10.8
ij>
我们启动ij
命令行工具。 我们将使用它来创建数据库和表。 Derby 系统目录位于/home/janbodnar/programming/derby/dbs
。
ij> CONNECT 'jdbc:derby://localhost:1527/testdb;create=true;
user=user12;password=34klq*';
我们创建testdb
数据库并连接到它。 我们提供用户凭证。
ij> run 'cars.sql';
我们执行cars.sql
脚本,该脚本创建CARS
表并将其填充数据。
ij> SELECT * FROM CARS;
ID |NAME |PRICE
------------------------------------------------------
1 |Audi |52642
2 |Mercedes |57127
3 |Skoda |9000
4 |Volvo |29000
5 |Bentley |350000
6 |Citroen |21000
7 |Hummer |41400
8 |Volkswagen |21600
8 rows selected
这是我们的CARS
表。 接下来,我们将创建一个 Java servlet,它将在 Web 浏览器中显示这些值。
项目
我们将创建一个简单的 Web 应用,该应用将连接到 Derby 数据库。 一个 Java Servlet 将连接到 Derby,并从CARS
表中检索所有数据。
$ tree
.
├── build.xml
├── context.xml
├── lib
│ └── servlet-api.jar
├── src
│ └── zetcode
│ └── SelectAllCars.java
└── web.xml
3 directories, 5 files
在当前工作目录中,我们有一个 Ant build.xml
文件,context.xml
配置文件,web.xml
部署描述符文件以及src
和lib
子目录。 build.xml
文件是 Ant 构建文件,它描述了构建,部署或清理项目的任务。 web.xml
定义了 Web 应用的结构。 在lib
目录中,有servlet-api.jar
文件,用于编译源文件。 (可以在 Tomcat 安装目录的lib
子目录中找到它。)在src
目录中,我们有 Java 源文件。
web.xml
文件定义 Web 应用的结构。
<?xml version="1.0" encoding="UTF8"?>
<web-app xmlns=“http://java.sun.com/xml/ns/javaee” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd” version=“3.0” metadata-complete=“true”>
<description>
Servlet which connects to Derby
</description>
<display-name>Derby, Tomcat</display-name>
<servlet>
<servlet-name>SelectAllCars</servlet-name>
<servlet-class>zetcode.SelectAllCars</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SelectAllCars</servlet-name>
<url-pattern>/SelectAllCars</url-pattern>
</servlet-mapping>
</web-app>
这些是web.xml
文件的内容。 在此文件中,我们注册SelectAllCars
servlet。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/testdb"
auth="Container"
type="javax.sql.DataSource"
username="user12"
password="34klq*"
driverClassName="org.apache.derby.jdbc.ClientDriver"
url="jdbc:derby://localhost:1527/testdb"
maxActive="10"
maxIdle="4"/>
</Context>
在context.xml
文件中,我们定义 JDBC 数据源。 可以为所有 Web 应用或单个应用定义context.xml
文件。 后者是我们的情况。
我们将显示 Ant 构建文件,该文件将用于构建和部署我们的小型应用。
<?xml version="1.0" ?>
<project name=“allcars” default=“deploy”>
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="dist.dir" value="dist"/>
<property name="deploy.dir" value="/home/janbodnar/bin/tomcat/webapps"/>
<echo>${ant.project.name}</echo>
<target name="init">
<mkdir dir="${build.dir}/classes" />
<mkdir dir="${dist.dir}"/>
<echo>Directories created.</echo>
</target>
<target name="compile" depends="init">
<javac srcdir="${src.dir}" destdir="${build.dir}/classes"
includeantruntime="false">
<classpath path="lib/servlet-api.jar"/>
</javac>
<echo>Source files compiled.</echo>
</target>
<target name="archive" depends="compile">
<war destfile="${dist.dir}/${ant.project.name}.war" webxml="web.xml">
<classes dir="${build.dir}/classes"/>
<metainf file="context.xml"/>
</war>
<echo>Archive created.</echo>
</target>
<target name="deploy" depends="archive">
<copy file="${dist.dir}/${ant.project.name}.war" todir="${deploy.dir}"/>
<echo>Project deployed.</echo>
</target>
<target name="clean">
<delete dir="${dist.dir}"/>
<delete dir="${build.dir}"/>
<echo>Project cleaned.</echo>
</target>
</project>
构建文件包括五个任务。 初始化任务将创建必要的目录。 编译任务将编译源代码。 存档任务将创建一个网络存档。 deploy 任务会将归档文件部署到 Tomcat 服务器。 最后,清洁任务将进行清洁。
以下是SelectAllCars
Servlet。
package zetcode;
import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource;
public class SelectAllCars extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = null;
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
out = response.getWriter();
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/testdb");
con = ds.getConnection();
st = con.createStatement();
out.println("<html>");
out.println("<head>");
out.println("<title>SimpleServlet</title>");
out.println("</head>");
out.println("<body>");
rs = st.executeQuery("SELECT * FROM CARS");
while (rs.next()) {
out.print(rs.getInt(1));
out.print(" ");
out.print(rs.getString(2));
out.print(" ");
out.print(rs.getString(3));
out.print("<br>");
}
out.println("</body>");
out.println("</html>");
} catch (NamingException | SQLException ex) {
Logger lgr = Logger.getLogger(SelectAllCars.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
} finally {
try {
if (rs != null) {
rs.close();
}
if (con != null) {
con.close();
}
if (out != null) {
out.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(SelectAllCars.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
}
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
在上面的 servlet 中,我们连接到 Derby testdb
数据库并从CARS
表中获取所有行。
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/testdb");
我们使用 JNDI 命名查找来获取数据源。 从数据源,我们创建连接对象。
rs = st.executeQuery("SELECT * FROM CARS");
while (rs.next()) { out.print(rs.getInt(1)); out.print(" “); out.print(rs.getString(2)); out.print(” “); out.print(rs.getString(3)); out.print(”<br>"); }
我们使用 SQL 语句从CARS
表中检索所有数据。 我们从结果集对象中打印数据。
$ ant
Buildfile: /home/janbodnar/programming/derby/servlet/build.xml
[echo] allcars
init: [mkdir] Created dir: /home/janbodnar/programming/derby/servlet/build/classes [mkdir] Created dir: /home/janbodnar/programming/derby/servlet/dist [echo] Directories created.
compile: [javac] Compiling 1 source file to /home/janbodnar/programming/derby/ servlet/build/classes [echo] Source files compiled.
archive: [war] Building war: /home/janbodnar/programming/derby/servlet/dist/allcars.war [echo] Archive created.
deploy: [copy] Copying 1 file to /home/janbodnar/bin/tomcat/webapps [echo] Project deployed.
BUILD SUCCESSFUL Total time: 1 second
我们启动 ant 来构建和部署项目。
图:SelectAllCars
servlet 的输出
Derby 工具
原文: http://zetcode.com/db/apachederbytutorial/tools/
在本章中,我们提到了 Derby 工具。 Derby 工具和工具是 Derby 随附的一组脚本。 它们通常用于创建,检查和更新 Derby 数据库。
在此页面中,我们将提及sysinfo
,dblook
,ij
,startNetworkServer
和stopNetworkServer
工具。
启动 Derby 工具
Derby 工具可以两种方式运行。 我们使用位于 Derby 安装目录的 bin 目录中的脚本名称,也可以使用derbyrun.jar
文件启动它们。
$ $DERBY_HOME/bin/ij
$ java -jar $DERBY_HOME/lib/derbyrun.jar ij
我们可以通过在终端中指定脚本名称来启动ij
工具。 第二行使用derbyrun.jar
文件运行ij
。
系统信息
sysinfo
工具提供有关操作系统,Java 和 Derby 的信息。 它将打印 Java 版本,Java 主目录,操作系统版本,Java 运行时版本,Derby 版本,当前和支持的语言环境。 该工具对于跟踪 Derby 的某些安装或配置问题很有用。
$ $DERBY_HOME/bin/sysinfo
------------------ Java Information ------------------
Java Version: 1.8.0_111
Java Vendor: Oracle Corporation
Java home: /home/janbodnar/bin/jdk1.8.0_111/jre
Java classpath: /home/janbodnar/bin/jdk1.8.0_111/db/lib/derby.jar:/home/janbodnar/bin/jdk1.8.0_111/db/lib/derbynet.jar:/home/janbodnar/bin/jdk1.8.0_111/db/lib/derbytools.jar:/home/janbodnar/bin/jdk1.8.0_111/db/lib/derbyoptionaltools.jar:/home/janbodnar/bin/jdk1.8.0_111/db/lib/derbyclient.jar
OS name: Linux
OS architecture: amd64
OS version: 4.4.0-66-generic
...
这是特定系统上提供的信息的摘录。
ij
ij
是一个交互式脚本工具。 它用于对 Derby 数据库运行脚本或交互式查询。
$ cat cars.sql
SET SCHEMA USER12;
CREATE TABLE CARS(ID BIGINT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY
(START WITH 1, INCREMENT BY 1), NAME VARCHAR(30), PRICE INT);
INSERT INTO CARS(Name, Price) VALUES('Audi', 52642);
INSERT INTO CARS(Name, Price) VALUES('Mercedes', 57127);
INSERT INTO CARS(Name, Price) VALUES('Skoda', 9000);
INSERT INTO CARS(Name, Price) VALUES('Volvo', 29000);
INSERT INTO CARS(Name, Price) VALUES('Bentley', 350000);
INSERT INTO CARS(Name, Price) VALUES('Citroen', 21000);
INSERT INTO CARS(Name, Price) VALUES('Hummer', 41400);
INSERT INTO CARS(Name, Price) VALUES('Volkswagen', 21600);
我们有一个cars.sql
文件,它创建一个数据库模式和一个CARS
表。
$ $DERBY_HOME/bin/ij
ij version 10.11
ij> CONNECT 'jdbc:derby:testdb;user=user12;create=true';
我们启动ij
工具。 我们创建一个testdb
数据库并建立连接。
ij> SHOW CONNECTIONS;
CONNECTION0* - jdbc:derby:testdb
* = current connection
SHOW CONNECTIONS
语句显示与 Derby 数据库的打开的连接。
ij> RUN 'cars.sql';
ij> CREATE SCHEMA USER12;
0 rows inserted/updated/deleted
ij> CREATE TABLE CARS(ID INT PRIMARY KEY, NAME VARCHAR(30), PRICE INT);
0 rows inserted/updated/deleted
ij> INSERT INTO CARS VALUES(1, 'Audi', 52642);
1 row inserted/updated/deleted
ij> INSERT INTO CARS VALUES(2, 'Mercedes', 57127);
1 row inserted/updated/deleted
ij> INSERT INTO CARS VALUES(3, 'Skoda', 9000);
...
我们加载并执行cars.sql
网站。 我们被告知正在进行的操作。
ij> SELECT * FROM CARS;
ID |NAME |PRICE
------------------------------------------------------
1 |Audi |52642
2 |Mercedes |57127
3 |Skoda |9000
4 |Volvo |29000
5 |Bentley |350000
6 |Citroen |21000
7 |Hummer |41400
8 |Volkswagen |21600
8 rows selected
我们从CARS
表中选择所有行。
ij> CONNECT 'jdbc:derby:testdb;shutdown=true';
ERROR 08006: Database 'testdb' shutdown.
在 Derby 中关闭数据库会导致异常。 预期错误 08006。
ij> SHOW CONNECTIONS;
No current connection
连接已关闭。
ij> EXIT;
我们使用EXIT
命令退出ij
工具。 请注意,每个命令后都有分号。
dblook
dblook
工具用于保存数据库对象的数据定义语言,包括表,视图,索引和触发器。
$DERBY_HOME/bin/dblook -d jdbc:derby:testdb
-- Timestamp: 2017-03-13 20:05:43.281
-- Source database is: testdb
-- Connection URL is: jdbc:derby:testdb
-- appendLogs: false
– DDL Statements for schemas
CREATE SCHEMA “USER12”;
– DDL Statements for tables
CREATE TABLE “USER12”.“CARS” (“ID” INTEGER NOT NULL, “NAME” VARCHAR(30), “PRICE” INTEGER);
CREATE TABLE “APP”.“CARS” (“ID” BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), “NAME” VARCHAR(30), “PRICE” INTEGER);
– DDL Statements for keys
– PRIMARY/UNIQUE ALTER TABLE “APP”.“CARS” ADD CONSTRAINT “SQL170313140819740” PRIMARY KEY (“ID”);
ALTER TABLE “USER12”.“CARS” ADD CONSTRAINT “SQL170313200304680” PRIMARY KEY (“ID”);
在上面的示例中,我们已从testdb
数据库中转储了对象。 使用-d
选项,我们提供了数据库的连接 URL。 在我们的案例中,dblook
工具保存了一个数据库架构和一个表。 使用-o
选项,可以将输出重定向到文件。
startNetworkServer
和stopNetworkServer
这些脚本启动和停止 Derby Network 服务器。 如果是联网服务器,则可以创建到 Derby 数据库的多个连接。
$ $DERBY_HOME/bin/startNetworkServer &
[1] 12421
$ Mon Mar 13 20:12:39 CET 2017 : Security manager installed using the Basic server security policy.
Mon Mar 13 20:12:40 CET 2017 : Apache Derby Network Server - 10.11.1.2 - (1629631) started and ready to accept connections
在这里,我们使用startNetworkServer
脚本启动 Derby Network Server。
ij> CONNECT 'jdbc:derby://localhost:1527/testdb';
在这里,我们通过 Derby Network Server 连接到testdb
数据库。 网络连接的连接 URL 是不同的。
ij> SELECT * FROM USER12.CARS;
ID |NAME |PRICE
------------------------------------------------------
1 |Audi |52642
2 |Mercedes |57127
3 |Skoda |9000
4 |Volvo |29000
5 |Bentley |350000
6 |Citroen |21000
7 |Hummer |41400
8 |Volkswagen |21600
8 rows selected
我们从CARS
表中选择所有汽车。 由于我们没有在连接 URL 中提供数据库模式,因此我们现在必须指定它。 数据库模式是用户名; 在我们的情况下USER12
。
$ $DERBY_HOME/bin/stopNetworkServer
Mon Mar 13 20:15:42 CET 2017 : Apache Derby Network Server - 10.11.1.2 - (1629631) shutdown
$ Mon Mar 13 20:15:42 CET 2017 : Apache Derby Network Server - 10.11.1.2 - (1629631) shutdown
我们已经使用stopNetworkServer
脚本停止了服务器。
NetworkServerControl
NetworkServerControl
是一个系统工具,可以启动和停止 Derby 网络服务器并配置或检索诊断信息。 除ping
以外,所有命令只能从运行服务器的计算机上执行。
$ $DERBY_HOME/bin/NetworkServerControl start &
使用start
命令,我们启动 Derby 服务器。
$ $DERBY_HOME/bin/NetworkServerControl ping
Tue Mar 21 15:53:29 CET 2017 : Connection obtained for host: localhost, port number 1527.
ping
命令测试 Derby 服务器是否已启动。
$ $DERBY_HOME/bin/NetworkServerControl sysinfo
--------- Derby Network Server Information --------
Version: CSS10110/10.11.1.2 - (1629631) Build: 1629631 DRDA Product Id: CSS10110
-- listing properties --
derby.drda.traceDirectory=/home/janbodnar/.derby/
derby.drda.maxThreads=0
derby.drda.sslMode=off
derby.drda.keepAlive=true
...
sysinfo
命令提供系统信息。
$ $DERBY_HOME/bin/NetworkServerControl runtimeinfo
--- Derby Network Server Runtime Information ---
---------- Session Information ---------------
Session # :3
-------------------------------------------------------------
# Connection Threads : 1
# Active Sessions : 1
# Waiting Sessions : 0
Total Memory : 78643200 Free Memory : 75359512
runtimeinfo
命令提供有关正在运行的网络服务器的会话,线程,预备语句以及内存使用的大量调试信息。
$ $DERBY_HOME/bin/NetworkServerControl shutdown
Tue Mar 21 15:56:43 CET 2017 : Apache Derby Network Server - 10.11.1.2 - (1629631) shutdown
Tue Mar 21 15:56:44 CET 2017 : Apache Derby Network Server - 10.11.1.2 - (1629631) shutdown
shutdown
命令停止 Derby 服务器。
在本章中,我们写了有关 Derby 工具的文章。
我们导航到localhost:8080/allcars/SelectAllCars
URL 并接收输出。
在本章中,我们使用了 Derby 和 Apache Tomcat。