所需属性以及无参构造
//url用来指定连接哪台电脑的什么数据库,以及数据库端口,和数据库名称
private static final String URL = "jdbc:mysql:///";
//数据库名称
private static final String DB_NAME = "aaa";
//数据库账户
private static final String USENAME = "root";
//数据库密码
private static final String PASSWORD = "123456";
//数据库连接对象
private static Connection con;
//获取预编译对像,因为是预编译对象所以在获取的时候就需要将sql语句传递进去。
private static PreparedStatement ps;
//sql语句查询的结果集
private static ResultSet rs;
//无参构造
private DBUtil(){
}
1:获取连接
/**
* 1:获取连接
* @return
*/
public static Connection getConnection(){
try {
//URL正常写法jdbc:mysql://192.169.218.204:3306/aaa(3306端口号),连接本地可以不写IP和端口号
con = DriverManager.getConnection(URL+DB_NAME, USENAME, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
2.获取预编译对像
/**
* 2:获取预编译对像
* @param sql 要执行的sql语句
* @return
*/
public static PreparedStatement getPS(String sql){
getConnection();
try {
ps = con.prepareStatement(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return ps;
}
3:编写关闭结果集对象的方法(方法重载)
/**
* 3:编写关闭结果集对象的方法
* @param con
*/
public static void close(Connection con){
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 4:编写关闭结果集对象的方法
* @param con
* @param ps
*/
public static void close(Connection con,PreparedStatement ps){
if(ps!=null){
try {
ps.close();
close(con);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 5:编写关闭结果集对象的方法
* @param con
* @param ps
* @param rs
*/
public static void close(Connection con,PreparedStatement ps,ResultSet rs){
if(rs!=null){
try {
rs.close();
close(con,ps);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4:向数据库中增加数据的通用方法
/**
* 通用的增加方法:
* 1:有多少个占位符,传入的model中有多少个属性有值。
* 2:model属性的书写顺序要与数据库的顺序一致
* @param sql语句
* @param e
*/
public static <E> void saveModel(String sql,E e){
getPS(sql);
try {
//通过反射获得E的class对象
Class<?> class1 = e.getClass();
//获取class对象的属性集
Field[] df = class1.getDeclaredFields();
int j=1;
for (int i = 0; i < df.length; i++) {
//破坏属性的访问修饰符
df[i].setAccessible(true);
//如果为空,说明添加数据时没有加入这个属性,直接跳过
if(df[i].get(e) != null){
//向sql语句的占位符中传参
ps.setObject(j++, df[i].get(e));
}
}
//将sql语句提交到数据库
ps.executeUpdate();
} catch (Exception ee) {
ee.printStackTrace();
}finally{
close(con,ps);
}
}
5:将数据库中的数据修改的通用方法
/**
* 通用修改方法
* @param sql
* @param e
*/
public static <E> void updateModel(String sql,E e){
getPS(sql);
try {
Class<?> class1 = e.getClass();
Field[] df = class1.getDeclaredFields();
int j=1;
//通过主键进行修改,一般主键都是表的第一列,所以i从1开始,将下标为0的属性放到最后。
for (int i = 1; i < df.length; i++) {
df[i].setAccessible(true);
if(df[i].get(e) != null){
ps.setObject(j++, df[i].get(e));
}
}
df[0].setAccessible(true);
//将对应主键的属性值,传入sql的占位符中
ps.setObject(j,df[0].get(e));
ps.execute();
} catch (Exception ee) {
ee.printStackTrace();
}finally{
close(con,ps);
}
}
6.通用的dml(增删改),有bug,使用麻烦
//Object...可以传入多个属性
public static void dml(String sql,Object...objects){
getPS(sql);
try {
for (int i = 0; i < objects.length; i++) {
//将传入来的objects依次放入sql语句的占位符中
ps.setObject(i+1, objects[i]);
}
//将sql语句提交到数据库运行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
}finally{
close(con,ps);
}
}
7.通用dql查找结果集为1
public static <E> E dqlOne(String sql,Class<E> c,Object...objects){
getPS(sql);
E e = null;//声明返回的值
try {
for (int i = 0; i < objects.length; i++) {
//将传入来的objects依次放入sql语句的占位符中
ps.setObject(i+1, objects[i]);
}
rs = ps.executeQuery();
//首先获取结果集中的所有列的集合。
ResultSetMetaData data = rs.getMetaData();
//根据列的数量创建一个字符串数组。
int count = data.getColumnCount();
//将所有的列名称存入到字符串数组之内
String[] str = new String[count];
for (int i = 0; i < str.length; i++) {
str[i] = data.getColumnLabel(i+1);
}
//调用method方法将获取的列名称成与类属性相同的字符串
String[] fields = method(str);
//如果要查询的结果集是个数字,将直接返回结果
if(c.getName().equals("int") || c.getName().equals("java.lang.Integer")){
rs.next();
return (E) new Integer(rs.getInt(1));
}
//开始遍历结果集。
while(rs.next()){
//因为本方法查询出的结果只为一条,查出多条要抛异常
if(rs.getRow()>1){
throw new Exception("查询结果应是1条结果,但是查出多条结果!");
}
//通过反射获取类的对象
e = c.newInstance();
//通过循环给e对象的属性赋值
for (int i = 0; i < str.length; i++) {
//使用列名通过反射对象,获取对象的属性。
Field field = c.getDeclaredField(fields[i]);
//公开属性的访问权限
field.setAccessible(true);
//给属性赋值
field.set(e, rs.getObject(str[i]));
}
}
} catch (Exception ee) {
ee.printStackTrace();
}finally{
close(con,ps,rs);
}
return e;
}
8:通用的DQL(查询多个结果的集合)
public static <E> List<E> dqlList(String sql,Class<E> c,Object...objects){
getPS(sql);
List<E> list = new ArrayList<>();
try {
for (int i = 0; i < objects.length; i++) {
ps.setObject(i+1, objects[i]);
}
rs = ps.executeQuery();
//首先获取结果集中的所有列的集合。
ResultSetMetaData data = rs.getMetaData();
//根据列的数量创建一个字符串数组。
int count = data.getColumnCount();
//将所有的列名称存入到字符串数组之内
String[] str = new String[count];
for (int i = 0; i < str.length; i++) {
str[i] = data.getColumnLabel(i+1);
}
String[] fields = method(str);
//开始遍历结果集。
while(rs.next()){
// 通过反射,将e实例化成对象。
E e = c.newInstance();
//通过循环给e对象的属性赋值
for (int i = 0; i < str.length; i++) {
//使用列名通过反射对象,获取对象的属性。
Field field = c.getDeclaredField(fields[i]);
//公开属性的访问权限
field.setAccessible(true);
//给属性赋值
field.set(e, rs.getObject(str[i]));
}
list.add(e);
}
} catch (Exception ee) {
ee.printStackTrace();
}finally{
close(con,ps,rs);
}
return list;
}
9.将列名转化成与属性名相同的字符串(method方法)
public static String[] method(String[] str){
String[] fields = new String[str.length];
for (int i = 0; i < fields.length; i++) {
//如果列名中有下划线,就进入if,没有就跳过,说明它与属性名一致
if(str[i].indexOf("_")!=-1){
//由于列名中可能不止一个下划线,所以做了如下处理:
//将列名以下划线进行分割,分割的结果放进一个数组
String[] split = str[i].split("_");
StringBuffer sb = new StringBuffer();
for (int j = 0; j < split.length; j++) {
if(j==0){
//直接拼接
sb.append(split[j]);
}else{
//将下划线后的单词转化为字符数组
char[] charArray = split[j].toCharArray();
//将第一个字符大写
charArray[0]-=32;
//拼接上这个单词
sb.append(charArray);
}
}
//将转化后的列名放进要返回的数组中
fields[i] = sb.toString();
}else{
//没有进if,说明它与属性名一致,直接放入数组中
fields[i] = str[i];
}
}
//返回已经放入和属性名一样的列名数组
return fields;
}
10.通用的分页查询,使用这个方法,会返回分页的各种数据.(所以返回值应为分页查询的对象)
public static <E> PageInfo<E> dqlListLim(String sql,Class<E> c, Object...objects){
//1:将传入的sql语句转化成求总数的sql
String sql1 = sql.toUpperCase();
StringBuffer sb = new StringBuffer("SELECT COUNT(*)");
sb.append(sql1.substring(sql1.indexOf("FROM")));
//2:去掉limit之后的sql
sb.replace(sb.indexOf("LIMIT"), sb.length(), "");
//3:去除掉参数中的分页参数
Object[] of = Arrays.copyOf(objects, objects.length-2);
Integer count = dqlOne(sb.toString(), int.class, of);
//4:修改参数执行原本的sql
int pageSize = (int) objects[objects.length-1];
int pageNumber = (int) objects[objects.length-2];
objects[objects.length-2]=(pageNumber-1)*pageSize;
List<E> data = dqlList(sql, c, objects);
PageInfo<E> PageInfo = new PageInfo<>(data,count,pageSize,pageNumber);
return PageInfo;
}
分页查询类:
public class PageInfo<E> {
/**
* 页中的数据
*/
//@NonNull //@NonNull表示这个属性不准为空,如果是空会抛空指针异常
private List<E> data;
/**
* 记录总条数
*/
@NonNull
private int count;
/**
* 每一页的行数
*/
private int pageSize;
/**
* 总页数
*/
private int countPage;
/**
* 当前页数
*/
private int pageNumber;
/**
* 开始页
*/
private int startPage;
/**
* 结束页
*/
private int endPage;
/**
* 上一页
*/
private boolean upPage;
/**
* 下一页
*/
private boolean nextPage;
public PageInfo(List<E> data, @NonNull int count, int pageSize, int pageNumber) {
this.data = data; //数据
this.count = count; //总数
this.pageSize = pageSize; //每页显示多少数据
this.pageNumber = pageNumber; //当前页码
this.countPage = count % pageSize == 0 ? count / pageSize : (count / pageSize)+1;
this.startPage=1;
this.endPage=countPage;
this.upPage=pageNumber==1?false:true;
this.nextPage=pageNumber==endPage?false:true;
}
}