1. 什么是DAO模式?
所谓的dao模式其实无非就是将数据库相关的CRUD操作封装在一个dao接口中,底层操作的仍旧是jdbc。
即DAO模式对外直接提供进行CRUD的各个数据库级别的操作接口.
注意原生jdbc也能实现dao模式。
但是原生 jdbc 实现dao的扩展性不高,原因就是下述的几点,所以本项目中接下来会直接使用mybatis框架实现dao模式。
jdbc编程的缺点:
1、每次操作数据库都要经历加载驱动、建立连接等步骤,频繁开启和关闭数据库连接浪费了数据库的资源(即每次都完整执行”加建创执处关”这6个步骤)。
设想:通过数据源(连接池)进行管理,连接池一般都是底层框架实现好的(言外之意就是数据源信息配置到文件(.xml或者.properties)中或者配置到JNDI中);
2、每次的sql,输入参数(占位符号)和输出参数(输出结果集)都被硬编码(写死在代码中),不灵活,改动sql还得重新编译java源文件。
设想:将sql的编写,输入参数和输出参数的编写和类型的映射关系通过xml文件或者注解的方式进行配置化管理。
2. 原生jdbc编写CRUD
2.1 创建后续整个mybatis所需要的实体类
>我们先创建整个mybatis案例中所需要的所有实体类,后面整个mybatis的介绍用使用的实体类都来自下面。
zeh.mybatis.code00common.entity.ZehPerson:
package zeh.mybatis.code00common.entity;
import java.util.Date;
public class ZehPerson {
private Long id;
private String name;
private Long age;
private String sex;
private Date birthday;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public Long getAge() {
return age;
}
public void setAge(Long age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex == null ? null : sex.trim();
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
zeh.mybatis.code00common.entity.ZehUser:
package zeh.mybatis.code00common.entity;
public class ZehUser {
private Long id;
private String name;
private Long age;
private String sex;
private String hobby;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public Long getAge() {
return age;
}
public void setAge(Long age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex == null ? null : sex.trim();
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby == null ? null : hobby.trim();
}
}
基于单表查询的实体类: zeh.mybatis.code00common.po.singleton.CommonPo
package zeh.mybatis.code00common.po.singleton;
import java.io.Serializable;
import java.util.List;
/**
* 定义pojo:
* (1)、建议和指定的表结构中的字段和类型保持一致,不能多也不能少。
* (2)、实际上,pojo实体不必要和表保持一致。但建议保持一致,如果要扩展属性,则新建一个子类作为po类继承原有实体即可。
* 原理是:对于要执行的sql(crud),需要的字段只需要和parameterType、resultType或者resultMap中规定的保持一致即可。
* (3)、在执行对应的 statementId 时,如果执行sql需要的字段和parameterType、resultType或者resultMap中依赖的pojo中不一致,将无法正确映射表字段和po对象实体间的关系。
* (4)、实体pojo和对应表之间的映射是通过parameterType/resultType/resultMap属性进行确定的,所以实体类名不用和表名称保持一致,会根据配置
* 的parameterType/resultType/resultMap自动将入参和结果集映射成对应pojo中的对应字段。
* (5)、resultType默认采用mybatis底层执行的规则(表字段名和属性名采用驼峰,自动去掉_)进行自动映射,如果pojo和表字段需要手动映射,需要采取两种方式之一:
* a、在mapper.xml映射文件中定义resultMap将表中查询出来的字段名和pojo中的属性名称进行映射。
* b、在执行sql时,将查询出来的表字段名使用 AS 起个别名,别名对应pojo中属性名。
* (6)、resultType其实本身也是一种resultMap,只不过其查询出来的字段值(本身是存放在List<Map<String,Object>>)会自动映射成pojo中的成员变量。
* <p>
* 该po对象对应的物理表是:ZEH_USER
*
* @author zhaoeh
*/
public class CommonPo implements Serializable {
//mybatis的二级缓存,其中resultType指定的类型对应的pojo类必须实现序列化接口,表示该查询结果可以被二级缓存进行序列化
private static final long serialVersionUID = 1L;
private int id;
private String name;
private int age;
private String sex;
//删除 hobby 的getter方法,证明 #{}和${}取值原则:优先按照 getXXX 或者 isXXX 反射 XXX 取值;如果没有getXXX 或者 isXXX,则直接反射对应的属性名即 hobby。
private String hobby;
//自定义属性,表中不存在的字段属性,完全不影响和表字段之间的映射关系。
private String testProperty;
private List<String> allList;
//自定义整数类型的动态表名后缀,验证是否在insert语句中传入动态表名参数总是报错
private Integer tableName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// getSex()方法手动指定返回值,则优先取该值。
public String getSex() {
return "不男不女";
}
public void setSex(String sex) {
this.sex = sex;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getTestProperty() {
return testProperty;
}
public void setTestProperty(String testProperty) {
this.testProperty = testProperty;
}
public List<String> getAllList() {
return allList;
}
public void setAllList(List<String> allList) {
this.allList = allList;
}
//isZhao()和getZhao()方法同一个pojo中只能定义一个,否则mybatis在反射的时候不知道该反射哪一个方法。
// public boolean getZhao() {
// return true;
// }
/**
* 定义isXXX()方法,验证 if 标签的boolean表达式是根据XXX反射的isXXX方法,而不是反射的属性。
* <p>
* 结论:是优先根据XXX反射isXXX()或者getXXX()得到返回值,没有对应的getXXX()或者isXXX()方法才反射属性。
*
* @return
*/
public boolean isZhao() {
return true;
}
/**
* 定义getXXX()方法,验证 if 标签的boolean表达式是根据XXX反射的getXXX方法,而不是反射的属性。
* <p>
* 结论:是优先根据XXX反射isXXX()或者getXXX()得到返回值,没有对应的getXXX()或者isXXX()方法才反射属性。
*
* @return
*/
public boolean getYui() {
return true;
}
/**
* 不定义为成员而是直接写一个getXXX()方法。
* 验证mybatis 的 #{} 和${}都是优先根据XXX反射的getXXX()或者isXXX()方法,没有getXXX()方法才反射的属性。
* 结论:是优先根据XXX反射isXXX()或者getXXX()得到返回值,没有对应的getXXX()或者isXXX()方法才反射属性。
*
* @return
*/
public String getMyName() {
return "getMyName";
}
/**
* 不定义为成员而是直接写一个isXXX()方法。
* <p>
* 验证mybatis 的 #{} 和${}都是根据XXX反射的getXXX()或者isXXX()方法而不是反射的属性。
* <p>
* 结论:是优先根据XXX反射isXXX()或者getXXX()得到返回值,没有对应的getXXX()或者isXXX()方法才反射属性。
*
* @return
*/
public String isUserName() {
return "isUserName";
}
public Integer getTableName() {
return tableName;
}
public void setTableName(Integer tableName) {
this.tableName = tableName;
}
@Override
public String toString() {
return "[id = " + this.getId() + ";name = " + this.getName() + ";age = " + this.getAge() + ";sex = " + this.getSex() + ";hobby = " + this.hobby + "]";
}
}
zeh.mybatis.code00common.po.singleton.UserCustomVo
package zeh.mybatis.code00common.po.singleton;
import java.io.Serializable;
/**
* 功能描述:
* (1)、po类的扩展类。
* (2)、一般要定义vo类引用po类时,最好不要修改原来的po类,而是重新扩展出一个新的子类对原来的vo进行补充。
* 因为有可能原来的vo类已经被很多其他类引用,如果不扩展子类将会引起高耦合。
*
* @params:
* @return:
* @author: zhaoerhu
* @date: 2019/9/6 16:15
*/
public class UserCustomVo extends CommonPo implements Serializable {
private static final long serialVersionUID = 1L;
// 可以扩展用户的信息
}
zeh.mybatis.code00common.po.singleton.UserQueryVo
package zeh.mybatis.code00common.po.singleton;
import java.util.List;
/**
* 定义vo类:对简单po对象再次封装的类就是vo类,即向vo类中委托注入其他的po类。
*
* @author zhaoeh
*/
public class UserQueryVo {
// 传入多个id
private List<Integer> ids;
// 在这里包装所需要的查询条件
// 用户查询条件
private UserCustomVo userCustom;
public UserCustomVo getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustomVo userCustom) {
this.userCustom = userCustom;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
// 可以包装其它的查询条件,订单、商品
// ....
}
zeh.mybatis.code00common.po.singleton.ZehPersonPo
package zeh.mybatis.code00common.po.singleton;
import java.util.Date;
/**
* 功能描述:
* ZehPerson实体类,对应表是zeh_person
*
* @ClassName ZehPersonPo
* @Author zhaoerhu
* @Date 2019/7/23 11:18
*/
public class ZehPersonPo {
private int id;
private String name;
private int age;
private String sex;
private Date birthday;
private String testProperty;
//动态表名参数后缀
private Integer tableName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getTestProperty() {
return testProperty;
}
public void setTestProperty(String testProperty) {
this.testProperty = testProperty;
}
public Integer getTableName() {
return tableName;
}
public void setTableName(Integer tableName) {
this.tableName = tableName;
}
}
定义级联多表查询的实体类: zeh.mybatis.code00common.po.more.MarshallUser
package zeh.mybatis.code00common.po.more;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 用户信息po类。
* 必须和指定的表结构中的字段和类型保持一致,否则将无法正确映射表字段和po对象实体间的关系
*
* @类名称: User
* @作者: zhaoerhu
* @创建时间: 2019-4-5
* @修改时间: 2019-4-5上午9:29:04
* @备注:尊重每一行代码!
*/
public class MarshallUser implements Serializable {
private static final long serialVersionUID = 1950306035918930917L;
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
// 一个用户可能具备多个订单。用于多对多查询结果的实体依赖。
private List<MarshallOrders> orders;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<MarshallOrders> getOrders() {
return orders;
}
public void setOrders(List<MarshallOrders> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", address='" + address + '\'' +
", orders=" + orders +
'}';
}
}
zeh.mybatis.code00common.po.more.MarshallCustom
package zeh.mybatis.code00common.po.more;
/**
* po类的扩展类
*
* 一般要定义vo类引用po类时,最好不要修改原来的po类,而是重新扩展出一个新的子类对原来的vo进行补充
*
* 因为有可能原来的vo类已经被很多其他类引用,如果不扩展子类将会引起高耦合。
*
* @author zhaoeh
*
*/
public class MarshallCustom extends MarshallUser {
// 可以扩展用户的信息
}
zeh.mybatis.code00common.po.more.MarshallUserCustom
package zeh.mybatis.code00common.po.more;
import java.util.Date;
/**
* 用户信息的扩展vo。
*
* @类名称: UserCustomVo
* @作者: zhaoerhu
* @创建时间: 2019-4-5
* @修改时间: 2019-4-5上午9:30:30
* @备注:尊重每一行代码!
*/
public class MarshallUserCustom extends MarshallUser {
private static final long serialVersionUID = 3900305244996910319L;
// 这里添加扩展字段
private Date birthday_start;// 起始日期
private Date birthday_end;// 截止日期
public Date getBirthday_start() {
return birthday_start;
}
public void setBirthday_start(Date birthday_start) {
this.birthday_start = birthday_start;
}
public Date getBirthday_end() {
return birthday_end;
}
public void setBirthday_end(Date birthday_end) {
this.birthday_end = birthday_end;
}
}
zeh.mybatis.code00common.po.more.MarshallItems
package zeh.mybatis.code00common.po.more;
import java.util.Date;
/**
* 该包下的po和vo都是基于一对多查询、多对多查询的复杂查询的po类。
* <p>
* 一对多或者多对多的复杂查询和一对一的简单查询其实对于po类没有什么要求,各个po类之间几乎不需要彼此依赖。
* 对于一对多或者多对多的查询结果映射,一般存在两种方式:
* (1)、自己再独立定义一个po类来完成结果到po的映射,这个po可以通过继承其他po的方式;(注意查询结果映射的po往往里面保存的是简单类型)。
* (2)、如果不想独立定义一个po类,就想使用原有的po,那么可以在mapper.xml中通过associaction标签来映射复杂查询结果中的其他po的映射。
* 永远注意:不论哪种方式,对于查询结果的映射po,几乎不需要定义po之间的委托依赖关系,因为查询结果往往都是简单类型的。
* <p>
* 商品po类。
*
* @类名称: Items
* @作者: zhaoerhu
* @创建时间: 2019-4-5
* @修改时间: 2019-4-5上午9:26:23
* @备注:尊重每一行代码!
*/
public class MarshallItems {
private Integer id;
private String name;
private Float price;
private String pic;
private Date createtime;
private String detail;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic == null ? null : pic.trim();
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail == null ? null : detail.trim();
}
@Override
public String toString() {
return "MarshallItems{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", pic='" + pic + '\'' +
", createtime=" + createtime +
", detail='" + detail + '\'' +
'}';
}
}
zeh.mybatis.code00common.po.more.MarshallOrders
package zeh.mybatis.code00common.po.more;
import java.util.Date;
import java.util.List;
/**
* 订单po类。
*
* @类名称: Orders
* @作者: zhaoerhu
* @创建时间: 2019-4-5
* @修改时间: 2019-4-5上午9:26:52
* @备注:尊重每一行代码!
*/
public class MarshallOrders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
// 用户信息,一对一查询,用于使用resultMap进行关联查询时,必须要依赖的购买用户实体对象。
private MarshallUser user;
// 订单明细,一对多查询,用于使用resultMap进行关联查询时,必须要依赖的订单明细实体对象。
private List<MarshallOrderDetail> orderdetails;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number == null ? null : number.trim();
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note == null ? null : note.trim();
}
public MarshallUser getUser() {
return user;
}
public void setUser(MarshallUser user) {
this.user = user;
}
public List<MarshallOrderDetail> getOrderdetails() {
return orderdetails;
}
public void setOrderdetails(List<MarshallOrderDetail> orderdetails) {
this.orderdetails = orderdetails;
}
@Override
public String toString() {
return "MarshallOrders{" +
"id=" + id +
", userId=" + userId +
", number='" + number + '\'' +
", createtime=" + createtime +
", note='" + note + '\'' +
", user=" + user +
", orderdetails=" + orderdetails +
'}';
}
}
zeh.mybatis.code00common.po.more.MarshallOrdersCustom
package zeh.mybatis.code00common.po.more;
/**
* 订单自定义po,包括订单信息、用户信息。
* <p>
* 这种po通过继承的方式,相当于单独定义了一种返回结果,而没有采用对象之间的委托依赖关系。
*
* @类名称: OrdersCustom
* @作者: zhaoerhu
* @创建时间: 2019-4-5
* @修改时间: 2019-4-5上午9:28:10
* @备注:尊重每一行代码!
*/
public class MarshallOrdersCustom extends MarshallOrders {
private String username;// 用户名称
private String address;// 用户地址
private String sex; // 用户性别
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
zeh.mybatis.code00common.po.more.MarshallOrderDetail
package zeh.mybatis.code00common.po.more;
/**
* 订单明细po类。
*
* @类名称: Orderdetail
* @作者: zhaoerhu
* @创建时间: 2019-4-5
* @修改时间: 2019-4-5上午9:26:41
* @备注:尊重每一行代码!
*/
public class MarshallOrderDetail {
private Integer id;
private Integer ordersId;
private Integer itemsId;
private Integer itemsNum;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getOrdersId() {
return ordersId;
}
public void setOrdersId(Integer ordersId) {
this.ordersId = ordersId;
}
public Integer getItemsId() {
return itemsId;
}
public void setItemsId(Integer itemsId) {
this.itemsId = itemsId;
}
public Integer getItemsNum() {
return itemsNum;
}
public void setItemsNum(Integer itemsNum) {
this.itemsNum = itemsNum;
}
@Override
public String toString() {
return "MarshallOrderDetail{" +
"id=" + id +
", ordersId=" + ordersId +
", itemsId=" + itemsId +
", itemsNum=" + itemsNum +
'}';
}
}
zeh.mybatis.code00common.po.more.MarshallQueryVo
package zeh.mybatis.code00common.po.more;
import java.util.List;
/**
* 对于复杂查询条件进行封装,使用对象之间的委托依赖实现复杂查询参数的封装。
*
* @类名称: QueryVo
* @作者: zhaoerhu
* @创建时间: 2019-4-5
* @修改时间: 2019-4-5上午9:28:20
* @备注:尊重每一行代码!
*/
public class MarshallQueryVo {
private MarshallUser user;
// 自定义用户扩展类
private MarshallUserCustom userCustom;
// 传递多个用户id
private List<Integer> ids;
public MarshallUser getUser() {
return user;
}
public void setUser(MarshallUser user) {
this.user = user;
}
public MarshallUserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(MarshallUserCustom userCustom) {
this.userCustom = userCustom;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
工具类: zeh.mybatis.code00common.utils.UUIDUtils
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package zeh.mybatis.code00common.utils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* UUID的工具类
*
* @类名称: UUIDUtils
* @作者: zhaoerhu
* @创建时间: 2019-4-29
* @修改时间: 2019-4-29下午9:02:35
* @备注:尊重每一行代码!
*/
public class UUIDUtils {
static Logger logger = LoggerFactory.getLogger(UUIDUtils.class);
private static SecureRandom secureRandom = null;
private static String netAddressHexStr = null;
private static String portHexStr = "0000";
private static byte[] addressBytes = null;
private static int nextSeq32767 = 0;
private static int nextSeq999 = 0;
private static char[] radixDigits = new char[]{'0', '1', '2', '3', '4',
'5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z'};
private UUIDUtils() {
}
public static String getStringValue() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
public static String generate() {
StringBuffer uid = new StringBuffer(32);
uid.append(getSystemMillisRadix32());
uid.append(getSeqRadix32());
uid.append(obtainNetAddressHexStr());
uid.append(portHexStr);
uid.append(toHex(getRandom(), 8));
return uid.toString();
}
public static long getUniqueLong() {
long longValue = System.currentTimeMillis();
longValue *= 1000000L;
long ipv4_lastNumber = (long) ((obtainAddressBytes()[3] & 255) * 1000);
longValue = longValue + ipv4_lastNumber + (long) getSeq999();
return longValue;
}
private static String getSystemMillisRadix32() {
String millisStr = Long.toString(System.currentTimeMillis(), 32)
.toUpperCase();
int len = millisStr.length();
if (len < 9) {
StringBuffer buffer = new StringBuffer(10);
buffer.append(millisStr);
int offset = 9 - len;
for (int i = 0; i < offset; ++i) {
buffer.append("0");
}
millisStr = buffer.toString();
} else if (len > 9) {
millisStr = millisStr.substring(len - 9);
}
return millisStr;
}
private static synchronized int getRandom() {
if (secureRandom == null) {
secureRandom = new SecureRandom();
}
return secureRandom.nextInt();
}
private static String toHex(int value, int length) {
StringBuffer buffer = new StringBuffer(length);
int shift = length - 1 << 2;
int kk = -1;
while (true) {
++kk;
if (kk >= length) {
return buffer.toString();
}
buffer.append(radixDigits[value >> shift & 15]);
value <<= 4;
}
}
private static int toInt(byte[] bytes) {
int value = 0;
int aryLen = bytes.length;
for (int i = aryLen - 1; i >= 0; --i) {
value <<= 8;
value |= bytes[i] & 255;
}
return value;
}
private static synchronized int getSeq32767() {
int retv = nextSeq32767++;
if (nextSeq32767 >= 32768) {
nextSeq32767 = 0;
}
return retv;
}
private static String getSeqRadix32() {
String seqStr = Long.toString((long) getSeq32767(), 32).toUpperCase();
int len = seqStr.length();
if (len < 3) {
StringBuffer buffer = new StringBuffer(3);
int offset = 3 - len;
for (int i = 0; i < offset; ++i) {
buffer.append("0");
}
buffer.append(seqStr);
seqStr = buffer.toString();
} else if (len > 3) {
seqStr = seqStr.substring(len - 3);
}
return seqStr;
}
private static synchronized int getSeq999() {
int retValue = nextSeq999++;
if (nextSeq999 >= 1000) {
nextSeq999 = 0;
}
return retValue;
}
private static byte[] obtainAddressBytes() {
if (addressBytes == null) {
try {
addressBytes = InetAddress.getLocalHost().getAddress();
} catch (UnknownHostException var1) {
logger.error("获取当前机器 host 异常:" + var1.getMessage());
}
}
return addressBytes;
}
private static String obtainNetAddressHexStr() {
if (netAddressHexStr == null) {
netAddressHexStr = toHex(toInt(obtainAddressBytes()), 8);
}
return netAddressHexStr;
}
}
zeh.mybatis.code00common.utils.PageInfoLimitUtil
package zeh.mybatis.code00common.utils;
import com.github.pagehelper.PageInfo;
import java.util.List;
/**
* 功能描述:手动分页工具类
*
* @ClassName PageInfoLimit
* @Author zhaoerhu
* @Date 2020/3/27 11:12
*/
public class PageInfoLimitUtil {
/**
* 功能描述: 抽取方法,手动封装PageInfo参数。
*
* @params: []
* @return: void
* @author: zhaoerhu
* @date: 2020/2/24 18:31
*/
public static void pageInfoLimit(List list, PageInfo pageInfo, int pageNumParam, int pageSizeParam) {
//手动设置PageInfo参数,进行手动分页
int start = 0;
int end = 0;
int totalPages = 0;
int totalRecord = 0;
int pageSize = 0;
int size = 0;
int number = 0;
size = pageSizeParam;
number = pageNumParam;
pageSize = pageSizeParam;
totalRecord = list.size();
//设置总数
pageInfo.setTotal(totalRecord);
//设置每页的显示条数
pageInfo.setPageSize(size);
//设置要显示的是第几页的数据
pageInfo.setPageNum(number);
pageInfo.setSize(totalRecord);
//计算获取对应的要显示的数据
if (totalRecord % pageSize == 0) {
totalPages = totalRecord / pageSize;
} else {
totalPages = totalRecord / pageSize + 1;
}
pageInfo.setPages(totalPages);
//初始边界值计算
if (number == 1) {
start = 0;
pageInfo.setHasPreviousPage(false);
pageInfo.setPrePage(0);
pageInfo.setIsFirstPage(true);
} else {
start = pageInfo.getPageSize() * (pageInfo.getPageNum() - 1);
pageInfo.setHasPreviousPage(true);
pageInfo.setPrePage(number - 1);
pageInfo.setIsFirstPage(false);
}
pageInfo.setStartRow((number - 1) * pageSize);
//结束边界值计算
if ((start + pageInfo.getPageSize() > pageInfo.getTotal())) {
end = totalRecord;
pageInfo.setHasNextPage(false);
pageInfo.setIsLastPage(true);
pageInfo.setEndRow(totalRecord);
} else {
end = start + pageInfo.getPageSize();
pageInfo.setHasNextPage(true);
pageInfo.setNextPage(number + 1);
pageInfo.setIsLastPage(false);
pageInfo.setEndRow((number) * pageSize);
}
if (start < end && end <= totalRecord) {
pageInfo.setList(list.subList(start, end));
}
if (pageInfo.getSize() == 0) {
pageInfo.setStartRow(0);
pageInfo.setEndRow(0);
} else {
pageInfo.setStartRow(pageInfo.getStartRow() + 1);
pageInfo.setEndRow(pageInfo.getStartRow() - 1 + pageInfo.getSize());
}
pageInfo.setPages(totalPages);
pageInfo.setNavigateLastPage(totalPages > number ? number + 1 : totalPages);
}
/**
* 功能描述: 重载手动分页方法
*
* @params: [pageInfo, pageNumParam, pageSizeParam]
* @return: void
* @author: zhaoerhu
* @date: 2020/2/24 22:03
*/
public static void pageInfoLimit(PageInfo pageInfo, int pageNumParam, int pageSizeParam) {
List list = pageInfo.getList();
//手动设置PageInfo参数,进行手动分页
int pageSize = 0;
int size = 0;
int number = 0;
int start = 0;
int end = 0;
int totalPages = 0;
int totalRecord = 0;
size = pageSizeParam;
number = pageNumParam;
pageSize = pageSizeParam;
totalRecord = list.size();
//设置总数
pageInfo.setTotal(totalRecord);
//设置每页的显示条数
pageInfo.setPageSize(size);
//设置要显示的是第几页的数据
pageInfo.setPageNum(number);
pageInfo.setSize(totalRecord);
//计算获取对应的要显示的数据
if (totalRecord % pageSize == 0) {
totalPages = totalRecord / pageSize;
} else {
totalPages = totalRecord / pageSize + 1;
}
pageInfo.setPages(totalPages);
//初始边界值计算
if (number == 1) {
start = 0;
pageInfo.setHasPreviousPage(false);
pageInfo.setPrePage(0);
pageInfo.setIsFirstPage(true);
} else {
start = pageInfo.getPageSize() * (pageInfo.getPageNum() - 1);
pageInfo.setHasPreviousPage(true);
pageInfo.setPrePage(number - 1);
pageInfo.setIsFirstPage(false);
}
pageInfo.setStartRow((number - 1) * pageSize);
//结束边界值计算
if ((start + pageInfo.getPageSize() > pageInfo.getTotal())) {
end = totalRecord;
pageInfo.setHasNextPage(false);
pageInfo.setIsLastPage(true);
pageInfo.setEndRow(totalRecord);
} else {
end = start + pageInfo.getPageSize();
pageInfo.setHasNextPage(true);
pageInfo.setNextPage(number + 1);
pageInfo.setIsLastPage(false);
pageInfo.setEndRow((number) * pageSize);
}
if (start < end && end <= totalRecord) {
pageInfo.setList(list.subList(start, end));
}
if (pageInfo.getSize() == 0) {
pageInfo.setStartRow(0);
pageInfo.setEndRow(0);
} else {
pageInfo.setStartRow(pageInfo.getStartRow() + 1);
pageInfo.setEndRow(pageInfo.getStartRow() - 1 + pageInfo.getSize());
}
pageInfo.setPages(totalPages);
pageInfo.setNavigateLastPage(totalPages > number ? number + 1 : totalPages);
}
}
2.2 使用jdbc编写CRUD
通过jdbc实现DAO:
package zeh.mybatis.code01jdbc.dao;
import zeh.mybatis.code00common.entity.ZehPerson;
import java.sql.*;
import java.util.Date;
/**
* 传统的 jdbc 方式连接数据库进行model层的操作-JDBC原生方式实现DAO模式,使用JUnit进行测试。
* @author zhaoeh
*/
public class JdbcDao {
/**
* 功能描述: 原生jdbc实现Dao
*
* @params: [isPreparedStatement]
* @return: void
* @author: zhaoerhu
* @date: 2020/4/10 20:21
*/
public void process(Boolean isPreparedStatement) {
// 数据库连接
Connection connection = null;
// 预编译的Statement,使用预编译的Statement提高数据库性能;
// 之所以提高性能,就是因为sql语句是通过jdbc进行预编译后直接发送给数据库进行执行的,数据库不再需要进行sql命令的编译。
// 并且预编译操作采取参数化占位符的方式,能够防止sql注入。
PreparedStatement preparedStatement = null;
//非预编译的statement
Statement statement = null;
// 结果集
ResultSet resultSet = null;
try {
// 1.加载数据库驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2.通过驱动管理类建立数据库连接,输入用户名和密码,相当于最原始的数据源的功能
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "oracle", "oracle");
if (isPreparedStatement) {
// 预编译
// 定义sql语句 ?表示占位符,对于占位符的sql语句必须使用 prepareStatement 进行执行,prepareStatement 由jdbc进行预编译然后统一由数据库执行。
String sql = "SELECT * FROM ZEH_PERSON WHERE NAME = ?";
// 3.创建预处理statement对象。
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "赵二虎");
// 4.向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
} else {
// 非预编译
String queryParam = "\'赵二虎\'";
String sql = "SELECT * FROM ZEH_PERSON WHERE NAME = " + queryParam;
// 3.创建非预处理statement对象。非预处理的sql只能提前准备好,不能使用占位符,因为jdbc不预编译,所以准备好sql统一发送给数据库进行编译执行。
statement = connection.createStatement();
// 4.向数据库发出sql执行查询,查询出结果集
resultSet = statement.executeQuery(sql);
}
// 5.遍历处理查询结果集 resultSet
while (resultSet.next()) {
//可以看出,原生 jdbc 没有使用任何pojo映射和数据表字段之间的关系,而是直接从resultSet结果集中进行捞取的。
Long id = Long.parseLong(resultSet.getString("id"));
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
//将数据库中的date类型取出来是string字符串,然后通过SimpleDateFormat类格式化为Java中的Date类型,再取出其中的毫秒数,即自1970年后的毫秒数。
Date date = resultSet.getDate("birthday");
//通过原生jdbc从resultSet结果集中捞取到对应的字段值,可以手动将这些值封装到对应的实体类中。模拟ORM框架的映射原理。
ZehPerson zehPerson = new ZehPerson();
zehPerson.setId(id);
zehPerson.setName(name);
zehPerson.setSex(sex);
zehPerson.setBirthday(date);
printZehPerson(zehPerson);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6.关闭资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 功能描述: 打印封装好的 zehPerson 对象
*
* @params: [zehPerson]
* @return: void
* @author: zhaoerhu
* @date: 2020/4/10 20:44
*/
private void printZehPerson(ZehPerson zehPerson) {
/**
* oracle中的null值和空字符取出来是不是java中的null值?
* 答案:对于oracle而言,空字符就是null值,null值就是空字符,取出来的就是java中的null值而不是java中的空字符。
* 总结:oracle中没有空字符一说,存入的空字符就是null值,需要使用 is null 才能查询到。所以 oracle 中的空字符取出就是java中的null值(注意不是空格)。
*/
String sex = zehPerson.getSex();
System.out.println("sex == null ? " + (sex == null));
System.out.println("\"null\".equals(sex) ? " + ("null".equals(sex)));
System.out.println("\"\".equals(sex) ? " + ("".equals(sex)));
}
}
执行程序:
package zeh.mybatis.code01jdbc.run;
import org.junit.Before;
import org.junit.Test;
import zeh.mybatis.code01jdbc.dao.JdbcDao;
/**
* 通过JUnit测试jdbc传统方式操作数据库(即jdk自带的原生jdbc操作)。
*
* @类名称: JdbcDaoJunitRun
* @作者: zhaoerhu
* @创建时间: 2019-3-6
* @修改时间: 2019-3-6下午12:45:59
* @备注:尊重每一行代码!
*/
public class JdbcDaoRun {
//委托dao对象
private JdbcDao jdbcDao;
//@Before是Junit自带的注解,表示在@Test标注的方法前执行。
@Before
public void initJdbcDao() {
this.jdbcDao = new JdbcDao();
}
//@Test是Junit自带的注解,选中该方法,右键使用Junit运行,则会自动运行该方法,类似于main方法。
@Test
public void testJdbcDaoUsePrepared() {
jdbcDao.process(Boolean.TRUE);
}
@Test
public void testJdbcDaoNotUsePrepared() {
jdbcDao.process(Boolean.FALSE);
}
}
3. jdbc实现DAO的缺点
使用jdbc实现DAO模式,发现其中有大量的重复步骤,即模板化的冗余代码,而且灵活度很低。
文档信息
- 本文作者:Marshall