1、关于Java项目的应用层分层模型
传统的MVC简单易用,但是也有一些缺点:模型层分层太粗,融合了数据处理、业务处理等所有的功能,核心的复杂业务逻辑都放到模型层,导致模型层很乱等。所以比较适应场景:后端业务逻辑简单的服务,比如接口直接提供对数据库增删改查。
对于较为复杂的业务,后端可以分为:表现层controller(可以连接view视图层/也可以是api对外输出约定格式的数据)、逻辑层service(处理业务逻辑)、模型层beanI(entity实体对应数据库中字段)、数据访问层dao(等同mybatis中逆向工程生成mapper层/对数据库持久化操作,主要实现一些增删改查操作),优点是业务逻辑与数据层分离。
2、JDBC的操作流程
JDBC是Java定义的一套和数据库建立连接的规范(接口),那么各家数据库厂商,想要Java去操作各家的数据库,必须实现这套接口,我们把数据库厂商写的这套实现类,称之为数据库驱动。
1)导入数据库的jar包
2)加载驱动jar包
3)获取连接对象
4)获取操作对象
5)开始操作
6)释放资源
这里主要展示常用的DBTUtil数据库资源链接及数据库资源释放代码
package com.www.util;
import java.sql.*;
public class DBUtil {
/**
* 用于链接数据库,得到的结果是数据库的连接对象,链接对象具备了操作数据库的很多功能。=
* @return 链接对象
*/
public static Connection getConn(){
//1. 加载数据库驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//2. 获取数据库链接
try {
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/springframe?characterEncoding=utf8&useSSL=false","root","123456");
//3. 将链接返回给工具的使用者
return conn;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
/**
* 断开数据库资源的链接,用于释放资源
* @param conn 要释放链接
* @param statement 要释放的执行环境
* @param resultSet 要释放的结果集
*/
public static void close(Connection conn, Statement statement, ResultSet resultSet){
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
DAO层的UserBean中的一段展示代码
public class UserDaoImp implements BaseDao<User>{
private static final String SQL_INSERT = "insert into spring_addon_resume_user(name,age,city,address,email,phone,weixin,qq,weibo,sex,description) values(?,?,?,?,?,?,?,?,?,?,?)";
private static final String SQL_FIND_BY_USERID = "select * from spring_addon_resume_user where id=?";
@Override
public int insert(User o) {
//1. 得到链接
Connection conn = DBUtil.getConn();
PreparedStatement state = null;
try {
//2. 得到执行环境
state = conn.prepareStatement(SQL_INSERT, Statement.RETURN_GENERATED_KEYS);
//3. 向执行环境中,填充参数、
state.setString(1,o.getName());
state.setInt(2,o.getAge());
state.setString(3,o.getCity());
state.setString(4,o.getAddress());
state.setString(5,o.getEmail());
state.setString(6,o.getPhone());
state.setString(7,o.getWeixin());
state.setString(8,o.getQq());
state.setString(9,o.getWeibo());
state.setString(10,o.getSex());
state.setString(11,o.getDescription());
//4. 执行
state.executeUpdate();
ResultSet rs = state.getGeneratedKeys();
if(rs.next()){
//5. 将数据的插入结果返回
return rs.getInt(1);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//释放数据库资源
DBUtil.close(conn,state,null);
}
return -1;
}
3、其中使用 Statement.getGeneratedKeys() 获得自增键值的注意点
(1)为什么要用 rs.next()?
ResultSet
是带有头结点的结果集,初始时游标指向第一行之前也就是头结点的位置,只是一个标识。如果不使用next()
方法将它指向第一行的话,是什么都得不到的。
(2)getInt(1)的作用
getInt()
的参数为columnIndex
,即列序号,MySQL 的列序号是从 1 开始的。比如对于下面的表
要获得自增主键 id
也就是第 1 列的值,就要使用 getInt(1)
。