WEB 小案例 -- 网上书城(一)
距离上次写博客有两周了吧,最多的原因就是自己期末考试了,上课没听就只能在期末狠狠的复习了,毕竟已经挂科了。当然还是因为自己懒吧!!!废话不多说开始我们今天的正题,网上书城!
一、 新建数据表(MySQL 数据库)
对于网上书城其后台应该有存放商品即书籍信息的数据表(books),存放用户信息的数据表(userInfo),存放用户账户信息的数据表(account),存放交易记录的数据表(trade),存放对应交易记录所交易商品的信息的数据表(tradeItem)。其 SQL 语句如下:
1. account 数据表:
CREATE TABLE `account` (
`accountid` int(11) NOT NULL auto_increment,
`balance` float default NULL,
PRIMARY KEY (`accountid`)
) insert into `account`(`accountid`,`balance`) values (1,9740);
2. books 数据表:
CREATE TABLE `books` (
`Id` int(11) NOT NULL auto_increment,
`Author` varchar(30) NOT NULL,
`Title` varchar(30) NOT NULL,
`Price` float NOT NULL,
`Publishingdate` date NOT NULL,
`Salesamount` int(11) NOT NULL,
`Storenumber` int(11) NOT NULL,
`Remark` text NOT NULL,
PRIMARY KEY (`Id`)
) insert into `books`(`Id`,`Author`,`Title`,`Price`,`Publishingdate`,`Salesamount`,`Storenumber`,`Remark`) values (1,'Tom','Java 编程思想',50,'2009-06-22',17,83,'Good Java Book'),(2,'Jerry','Oracle DBA 教材',60,'2009-06-22',12,88,'Good Oracle Book'),(3,'Bob','Ruby',50,'2009-06-22',12,88,'Good 0'),(4,'Mike','Javascript',51,'2009-06-22',0,100,'Good 1'),(5,'Rose','Ajax',52,'2009-06-22',0,100,'Good 2'),(6,'Backham','Struts',53,'2009-06-22',0,100,'Good 3'),(7,'Zidon','Hibernate',54,'2009-06-22',2,12,'Good 4'),(8,'Ronaerdo','Spring',55,'2009-06-22',2,13,'Good 5'),(9,'Clinsman','Cvs',56,'2009-06-22',0,16,'Good 6'),(10,'Kaka','Seo',57,'2009-06-22',0,17,'Good 7'),(11,'Lauer','Lucence',58,'2009-06-22',0,18,'Good 8'),(12,'Kasi','Guice',59,'2009-06-22',0,19,'Good 9'),(13,'Prierlo','Mysql',60,'2009-06-22',6,14,'Good 10'),(14,'Haohaidong','DB2',61,'2009-06-22',9,12,'Good 11'),(15,'Feige','Sybase',62,'2009-06-22',8,14,'Good 12'),(16,'Tuoleisi','DBDesign',63,'2009-06-22',0,23,'Good 13'),(17,'Jielade','Eclipse',64,'2009-06-22',0,24,'Good 14'),(18,'Teli','Netbeans',65,'2009-06-22',0,25,'Good 15'),(19,'Lapade','C#',66,'2009-06-22',0,26,'Good 16'),(20,'Runi','JDBC',67,'2009-06-22',0,27,'Good 17'),(21,'JoeKeer','Php',68,'2009-06-22',0,28,'Good 18'),(22,'Jordan','MysqlFront',69,'2009-06-22',5,24,'Good 19'),(23,'Yaoming','NoteBook',70,'2009-06-22',5,25,'Good 20'),(24,'Yi','C',71,'2009-06-22',5,26,'Good 21'),(25,'Sun','Css',72,'2009-06-22',0,32,'Good 22'),(26,'Xuliang','JQuery',73,'2009-06-22',0,33,'Good 23'),(27,'Meixi','Ext',74,'2009-06-22',0,34,'Good 24'),(28,'Apple','iphone',75,'2009-06-22',0,35,'Good 25'),(29,'Aigo','dc',76,'2009-06-22',0,36,'Good 26'),(30,'Sony','psp',77,'2009-06-22',0,100,'Good 27'),(31,'IRiver','mp3',78,'2009-06-22',0,100,'Good 28'),(32,'Sansing','TV',79,'2009-06-22',0,100,'Good 29');
3. trade 数据表:
CREATE TABLE `trade` (
`tradeid` int(11) NOT NULL auto_increment,
`userid` int(11) NOT NULL,
`tradetime` datetime NOT NULL,
PRIMARY KEY (`tradeid`),
KEY `user_id_fk` (`userid`),
CONSTRAINT `user_id_fk` FOREIGN KEY (`userid`) REFERENCES `userinfo` (`userid`)
)
4. tradeItem 数据表:
CREATE TABLE `tradeitem` (
`itemid` int(11) NOT NULL auto_increment,
`bookid` int(11) default NULL,
`quantity` int(11) default NULL,
`tradeid` int(11) default NULL,
PRIMARY KEY (`itemid`),
KEY `book_id_fk` (`bookid`),
KEY `trade_id_fk` (`tradeid`),
CONSTRAINT `book_id_fk` FOREIGN KEY (`bookid`) REFERENCES `mybooks` (`Id`),
CONSTRAINT `trade_id_fk` FOREIGN KEY (`tradeid`) REFERENCES `trade` (`tradeid`)
)
5. userInfo 数据表:
CREATE TABLE `userinfo` (
`userid` int(11) NOT NULL auto_increment,
`username` varchar(50) default NULL,
`accountid` int(11) default NULL,
PRIMARY KEY (`userid`),
KEY `account_id_fk` (`accountid`),
CONSTRAINT `account_id_fk` FOREIGN KEY (`accountid`) REFERENCES `account` (`accountid`)
) insert into `userinfo`(`userid`,`username`,`accountid`) values (1,'yinyin',1);
6. shoppingCart 数据表:
CREATE TABLE `shoppingcart` (
`cart_id` int(11) NOT NULL auto_increment,
`user_id` int(11),
`cart_count` int(11),
`cart_name` varchar(50),
`cart_price` int(11),
PRIMARY KEY (`cart_id`),
KEY `user_id_fk` (`user_id`),
CONSTRAINT `user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `userinfo` (`accountid`)
)
二、 Domain 类以及 DAO 接口编写
我们已经将底层数据库编写完成,现在我们要以数据表为基础结合我们要实现的功能去设计 DAO 接口,以及根据数据表编写 Domain 类即一般的 java 类。Domain 类如下:
1. 结构
2. 我们结合数据表编写 Domain 类时需要清楚每一张表的功能,这样思路才可以更清晰
① Account
public class Account {
private int account_id;
private int balance; public Account(int balance) {
this.balance = balance;
} public Account() {} @Override
public String toString() {
return "Account{" +
"account_id=" + account_id +
", balance=" + balance +
'}';
} public int getAccount_id() {
return account_id;
} public void setAccount_id(int account_id) {
this.account_id = account_id;
} public int getBalance() {
return balance;
} public void setBalance(int balance) {
this.balance = balance;
}
}
② Books
import java.sql.Date; /**
* 依据数据表 Books 新建实体类 books
*/
public class Books {
private Integer id;
private String author;
private String title;
private Integer price;
private Date publishDate;
private Integer salesCount;
private Integer storeNumber;
private String remark; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getAuthor() {
return author;
} public void setAuthor(String author) {
this.author = author;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public Integer getPrice() {
return price;
} public void setPrice(Integer price) {
this.price = price;
} public Date getPublishDate() {
return publishDate;
} public void setPublishDate(Date publishDate) {
this.publishDate = publishDate;
} public Integer getSalesCount() {
return salesCount;
} public void setSalesCount(Integer salesCount) {
this.salesCount = salesCount;
} public Integer getStoreNumber() {
return storeNumber;
} public void setStoreNumber(Integer storeNumber) {
this.storeNumber = storeNumber;
} public String getRemark() {
return remark;
} public void setRemark(String remark) {
this.remark = remark;
} public Books() { } public Books(Integer id, String author, String title, Integer price, Date publishDate, Integer salesCount, Integer storeNumber, String remark) {
this.id = id;
this.author = author;
this.title = title;
this.price = price;
this.publishDate = publishDate;
this.salesCount = salesCount;
this.storeNumber = storeNumber;
this.remark = remark;
} public Books(String title, Integer price) {
this.title = title;
this.price = price;
} @Override
public String toString() {
return "Books{" +
"id=" + id +
", author='" + author + '\'' +
", title='" + title + '\'' +
", price=" + price +
", publishDate=" + publishDate +
", salesCount=" + salesCount +
", storeNumber=" + storeNumber +
", remark='" + remark + '\'' +
'}';
}
}
③ ShoppingCartItems ④ Trade ⑤ TradeItem ⑥ UserInfo
其他的 Domain 类和前面两个一样,都是根据数据表对应的列添加对应类型的变量,至于 Damain 类对应的 Dao 接口及其实现类我们后面根据具体功能编写添加。
三、 JDBC 实现
1. 连接数据库的工具类实现 JDBCTools.java 以及配置文件 c3p0-config.xml
package com.book.store.db; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException; /**
* 数据库工具类
*/
public class JDBCTools {
// 定义数据源
private static DataSource dataSource;
// 初始化数据源,静态代码块只会执行一次,提高了效率
static {
dataSource = new ComboPooledDataSource("bookStore");
}
/*
* 获取数据库连接
* */
public static Connection getConnection() {
Connection connection = null;
try {
// 从数据源总获取数据库连接
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/*
* 释放数据库连接
* */
public static void releaseConnection(Connection connection) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
<named-config name="bookStore">
<property name="user">root</property>
<property name="password">zy961029</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///bookshop</property>
</named-config>
</c3p0-config>
2. 增删改查操作类的设计(Dao.java)以及实现 (DaoImpl.java)
package com.book.store.dao; import java.util.List; /**
* 数据库基本操作
*/
public interface Dao<T> {
// 执行插入操作
long insert(String sql, Object ... args);
// 执行更新操作
void update(String sql, Object ... args);
// 查找对象集合 List
List<T> getList(String sql, Object ... args);
// 查找对象
T getValue(String sql, Object ... args);
// 查找单个值
Object getCount(String sql, Object ... args);
// 执行批量更新操作,
void batch(String sql, Object[] ... params);
}
DaoImpl.java(在这里我们使用 ThreadLocal 实现处理事务)
package com.book.store.impl; import com.book.store.dao.Dao;
import com.book.store.db.JDBCTools;
import com.book.store.web.ThreadLocalConnection;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.List; /**
* 使用 DBUtils 和 C3p0 实现操作数据库的基本方法
*/
public class DaoImpl<T> implements Dao<T> {
QueryRunner queryRunner;
Class<T> type;
// 使用反射动态创建实体类的 class
public DaoImpl() {
queryRunner = new QueryRunner();
Type superClass = getClass().getGenericSuperclass(); if (superClass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superClass; Type[] args = parameterizedType.getActualTypeArguments();
if (args != null && args.length > 0) {
if (args[0] instanceof Class) {
type = (Class<T>) args[0];
}
}
}
}
/*
* 我们在后面往表中插入数据后需要根据自动生成的主键值去操作其他数据表,所以我们这里使用原生 JDBC 代码去插入数据,并返回自动生成的主键值
* */
@Override
public long insert(String sql, Object... args) {
long id = 0;
// 获取过滤器中绑定的 connection 对象
Connection connection = ThreadLocalConnection.getInstance().get();
// 执行语句后的对象
ResultSet resultSet;
try {
// 获取 prepareStatement 对象,并设置返回自动生成的主键
PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// 给参数赋值
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
// 执行插入操作
preparedStatement.executeUpdate();
// 将返回结果赋值给 resultSet
resultSet = preparedStatement.getGeneratedKeys();
if (resultSet.next()) {
// 将结果赋值给 id
id = resultSet.getLong(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
return id;
}
/*
* 使用 DBUtils 更新操作
* */
@Override
public void update(String sql, Object... args) {
Connection connection = ThreadLocalConnection.getInstance().get(); try {
queryRunner.update(connection, sql, args);
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* 使用 DBUtils 获取对应对象的 list 集合
* */
@Override
public List<T> getList(String sql, Object... args) {
Connection connection = ThreadLocalConnection.getInstance().get();
List<T> list = null; try {
list = queryRunner.query(connection, sql, new BeanListHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
/*
* 使用 DBUtils 获取某一个对象
* */
@Override
public T getValue(String sql, Object... args) {
Connection connection = ThreadLocalConnection.getInstance().get();
T entity = null; try {
entity = queryRunner.query(connection, sql, new BeanHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
} return entity;
}
/*
* 执行批量更新操作(循环实现):完成交易的时候需要将此次交易信息批量插入数据表中,以及批量更新商品数据表的库存量和销售量等操作
* */
@Override
public void batch(String sql, Object[]... params) {
Connection connection = ThreadLocalConnection.getInstance().get(); try {
for (int i = 0; i < params.length; i++) {
queryRunner.update(connection, sql, params[i]);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* 获取某一个值:根据 Id 获取其他信息等
* */
@Override
public Object getCount(String sql, Object... args) {
Object totalNum = null;
Connection connection = ThreadLocalConnection.getInstance().get(); try {
totalNum = queryRunner.query(connection, sql, new ScalarHandler(), args);
} catch (SQLException e) {
e.printStackTrace();
}
return totalNum;
}
}
ThreadLocalConnection.java (事务操作的基类,单例实现使得结账操作中的多个操作使用一个数据库连接,从而完成事务操作)
package com.book.store.web; import java.sql.Connection; /**
* 封装处理事务的方法
*/
public class ThreadLocalConnection { private ThreadLocalConnection(){} private static ThreadLocalConnection instance = new ThreadLocalConnection(); public static ThreadLocalConnection getInstance() {
return instance;
} private ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<Connection>(); public void bind(Connection connection) {
connectionThreadLocal.set(connection);
} public Connection get() {
return connectionThreadLocal.get();
} public void remove() {
connectionThreadLocal.remove();
}
}
使用 ThreadLocal 处理事务,即通过 ThreadLocal.set() 将对象的引用保存到各线程的自己的一个 map 中,每个线程都有这样一个 map,执行 ThreadLocal.get() 时,各线程从自己的 map 中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal 实例是作为 map 的 key 来使用的,这样便可以在最后的结账操作事务中合法完成。
一般情况下,通过 ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程不需要访问,所以说 ThreadLocal 不能解决共享对象的多线程访问问题。
这次我们就先把有关数据库操作讲解完,后面我们接着这次继续讲解。如果有什么表述错误的地方欢迎大家指点,谢谢!!!
WEB 小案例 -- 网上书城(一)的更多相关文章
- WEB 小案例 -- 网上书城(四)
针对于这个小案例我们今天讲解结账操作,也是有关这个案例的最后一次博文,说实话这个案例的博文写的很糟糕,不知道该如何去表述自己的思路,所以内容有点水,其实说到底还是功力不够. 处理思路 点击结账,发送结 ...
- Web 小案例 -- 网上书城(三)
内容有点乱,有兴趣的同伙可依照后面的案例结构结合文章进行阅读 和网上购买东西一样,你可以在不登录的状态下去浏览商品,但是当你想把自己中意的东西加入购物车或是收藏起来就需要你拥有自己的账号然后登录后才可 ...
- WEB 小案例 -- 网上书城(二)
寒假结束了,自己的颓废时间同样结束了,早该继续写博客了,尽管我的格式以及内容由于各种原因老被卡,但必须坚持写下去!!! 上次我们对于本案例的数据库部分进行了阐述,这次主要接着上次的内容分享本案例的翻页 ...
- 02SpringMvc_springmvc快速入门小案例(XML版本)
这篇文章中,我们要写一个入门案例,去整体了解整个SpringMVC. 先给出整个项目的结构图:
- SqlDependency缓存数据库表小案例
SqlDependency的简介: SqlDependency是outputcache网页缓存的一个参数,它的作用是指定缓存失效的数据库依赖项,可以具体到数据库和表. SqlDependency能解决 ...
- MVC 小案例 -- 信息管理
前几次更新博客都是每次周日晚上到周一,这次是周一晚上开始写,肯定也是有原因的!那就是我的 Tomact 忽然报错,无法启动,错误信息如下!同时我的 win10 也崩了,重启之后连 WIFI 的标志也不 ...
- Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例
Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例 继上篇json解析,我用了原生的json解析,但是在有些情况下我们不得不承认,一些优秀的json解析框架确实十分的 ...
- 8天入门docker系列 —— 第五天 使用aspnetcore小案例熟悉容器互联和docker-compose一键部署
这一篇继续完善webnotebook,如果你读过上一篇的内容,你应该知道怎么去挂载webnotebook日志和容器的远程访问,但是这些还远不够,webnotebook 总要和一些数据库打交道吧,比如说 ...
- spring boot入门小案例
spring boot 入门小案例搭建 (1) 在Eclipse中新建一个maven project项目,目录结构如下所示: cn.com.rxyb中存放spring boot的启动类,applica ...
随机推荐
- Java 哲学家进餐
某次操作系统实验存档.V 这个哲学家除了吃就知道睡.( ╯□╰ ) 哲学家.java: package operating.entity.philosophyeating; import operat ...
- HTML基本功之文档结构
项目名 首页 命名为 index.html 样式文件夹 命名为 css /*用来放样式文件*/ base.css /*基本样式*/ index.css /*首页样式*/ global.css /* ...
- Java的演化-Java8实战笔记
一个语言要想一直有活力,它也需要跟随着时代的变化去进步,Java作为一个古老的语言,它其实有太多的历史包袱,在改变的过程中需要考虑很多,但是它也在慢慢的演变,巩固自己的城墙,不让自己被遗忘在历史中(不 ...
- 程序猿的日常——Java中的集合列表
列表对于日常开发来说实在是太常见了,以至于很多开发者习惯性的用到数组,就来一个ArrayList,根本不做过多的思考.其实列表里面还是有很多玩法的,有时候玩不好,搞出来bug还得定位半天.所以这里就再 ...
- ssh的action校验内容输出
当form里为input类型时,如<input type="text" name="manager.name" />,则在对应的jsp中要使用< ...
- gcc编译器用法
一个用c语言写的程序把他编译成计算机可执行的文件,一般有4个步骤 /*================================================================ ...
- [js高手之路]面向对象版本匀速运动框架
这篇文章的效果,需要看过以下3篇文章: [js插件开发教程]一步步开发一个可以定制配置的隔行变色小插件 [js高手之路]匀速运动与实例实战(侧边栏,淡入淡出) [js高手之路]打造通用的匀速运动框架 ...
- Transact-SQL参考--学习笔记
基本的就不累赘了. 运算符 除法: dividend / divisor 如果用一个整数的 divisor 去除整数的 dividend,其结果是一个整数,小数部分被截断,如果要有小数可以将divid ...
- Python Tornado篇
Tornado既是一个web server,也是web framework.而它作为web server 采用的是asynchronous IO的网络模型,这是一种很高效的模型. Tornado 和现 ...
- JavaScript(五)语句
js 的语句有 表达式语句, 复合语句{}, 空语句, 声明语句 if 默认不写大括号 可以执行 紧接着的一行 do-while do{}while() while for(初始化:判断:更新){执 ...