开发工具与关键技术:MyEclipse 10、JAVA、SQLyogEnt
作者:曾浩源
撰写时间:2019年05月14日
例如MySQL有一个User表,需要将它遍历到页面上:
首先有如下步骤:
1、为项目引入MySQL驱动(jar包),这个很简单就不用说了
2、创建po包 (存放数据的实体类)
3、创建common包 (存放公告类、接口、抽选方法)
4、创建dao包 (存放数据库操作接口)
5、创建until (存放工具类)
一、创建po包后、创建个User实体类
例如:MySQL数据库的user表的字段有:
userid,username,password 三个字段
在User实体类里添加以这三个字段为名称的三个私有变量 并创建相对应的getter和setter方法。
二、创建common包后:
先想一下,以后如果有多个表都需要进行增删查改,所有方法的相同点有什么?
首先要想到的有五种:
1、查询该表的所有数据
2、根据id查询出一条数据
3、根据一条数据进行新增操作
4、根据一条数据进行修改操作
5、根据id删除一条数据
创建一个序列化的接口:T表示实体类,K表示实体类里的主键类型(表内的标识符)
public interface BaseDao<T,K extends Serializable> {
//创建五个抽象方法
List<T> selectAll(); //查询表内的所有数据,并返回到实体类集合list中
T findById(int id); //根据id查询出数据,返回到实体类T中
int update(T t); //得到一个实体类对其进行修改操作
int insert(T t); //得到一个实体类对其进行新增操作
int deleteById(int id); //根据一个id查询出数据,对其进行删除操作
}
三、创建dao包后:
1、dao包是存放数据库操作的接口,而common是存放公共类、接口等,现在需要对User表里的数据进行操作(DML),也包含了增删查改,所以我们在新建接口时可以继承需要的公共接口。
创建一个接口IUserDao继承BaseDao,在接口中还可以添加属于自己的抽象方法,例如:根据username和password查询出一条数据。
User findByUsernameAndPassword(String username, String password);
2、创建好接口后,就有了良好的模板,最后就是实现它:创建实现类。
创建实现类前,要想到,实现类放在哪个包?
所以就有了dao.impl这个包来存放实现dao接口的类。
3、创建UserDaoImpl实现类,实现接口IUserDao。最后要实现所有的抽象方法,包括common包里的BaseDao接口里的抽象方法。
4、那么问题来了,dao包里是对数据进行操作的接口,dao.impl包里是对数据进行操作的类,要对MySQL的数据进行操作(DML),之前要做的肯定是连接数据库。怎么连接MySQL数据库?
四、创建until包:存放工具类(连接数据库的方法可以封装为一个工具类)
虽然在dao.impl包的类里可以直接进行连接数据库的操作,但连接数据库的方法在java却是千篇一律:不同的只有(四个参数):
1、username用户名 2、password 密码 3、url 数据库连接地址
4、driver 各个数据库连接驱动(jar包)
所以我们只需要用jdbc.properties文件将四个参数以键值对的方法存储,到时候根据文件流的方式获取。
其余的连接数据的内容都是一模一样的,最后就需要用一个工具类将他们封装起来。
(1)创建工具类DBUtil后,首先创建四个私有的参数变量,然后使用静态代码块获取jdbc.properties文件里四个参数:
InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
pro.load(in);
并赋值给参数变量。
(2)创建getConnection()方法,返回Connection,即连接对象方法
Class.forName(driver);
con = DriverManager.getConnection(url, username, password);
(3)创建close(),即关闭数据库资源方法(结果集ResultSet rs,制备语句对象(表示预编译SQL语句的对象)PreparedStatement ps,连接对象Connection con)关闭的顺序也是如此。
例如:rs.close()关闭前都需要对其进行判断是否为null。
五、until包内的DBUtil类(连接数据库工具类)编写完后,连接数据库就很方便了。回到UserDaoImpl实现类,可以编写对数据库的增删查改操作了。
首先声明三个私有变量,即:连接对象con,制备语句对象 ps,结果集 rs。最后就可以编写方法了:
1、查询user表内所有的数据,返回到user实体类集合list中。
private String selectAll = “select * from user”;//方法外声明sql语句的字符串
selectAll方法里:
List<User> users = new ArrayList<User>();//实例化一个实体类的集合
con = DBUtil.getConnection();//调用工具类获取con
ps = con.prepareStatement(selectAll);//根据sql制备语句
rs = ps.executeQuery();//执行sql语句,并得到结果赋值给结果集
while (rs.next()) {//循环结果集,将得到数据赋值给实体类
User user = new User();
user.setUserid(rs.getInt("userid"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
users.add(user);//将实体类添加进集合
}
DBUtil.close(con, ps, rs);//关闭资源
return users;//返回实体类集合
2、根据id查询出数据,返回到实体类User中:
private String findById = "select * from user where userid=?";//方法外声明sql语句的字符串
User user = new User();//初始化一个实体类
con = DBUtil.getConnection();//调用工具类获取con
ps = con.prepareStatement(findById);//根据sql制备语句
ps.setInt(1, id);//为sql语句中的第一个?设置值,?为占位符
rs = ps.executeQuery();//执行sql语句,并得到结果赋值给结果集
while (rs.next()) {//循环结果集,将得到数据赋值给实体类
user.setUserid(rs.getInt("userid"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
DBUtil.close(con, ps, rs);//关闭资源
return user;//返回实体类
3、得到一个实体类User对其进行新增操作:
//方法外声明sql语句的字符串
private String insert = "insert into user(username,password) values (?,?)";
int flog = 0;//声明int类变量,用于存储进行新增操作过返回的数据
con = DBUtil.getConnection();//调用工具类获取con
con.setAutoCommit(false);//设置自动提交为关闭,即为开启事务
ps = con.prepareStatement(insert);//根据sql制备语句
ps.setString(1, user.getUsername());//设置占位符的值(username)
ps.setString(2, user.getPassword());//设置占位符的值(password)
flog = ps.executeUpdate();//执行sql语句,返回数据为,新增(改变)多少行
con.commit();//提交
【con.rollback();//在处理异常时回滚】
DBUtil.close(con, ps, rs);//关闭资源
return flog;//返回改变行数
4、其余的都差不多一样了,需要注意的是:
(1)每个都中需要抛出或处理异常,处理异常时,需要将关闭资源的方法写在finally的代码块内。
(2)查询时执行sql语句为ps.executeQuery(); 该方法的返回类型为结果集
而增删查改都是ps.executeUpdate(); 该方法的返回类型为int,改动多少行。
(3)在新增时,可返回新增的主键是多少:
在为ps赋值时:
ps = con.prepareStatement
(insert,Statement.RETURN_GENERATED_KEYS);
rs=ps.getGeneratedKeys();//将得到的结果赋值给结果集
long keys=0;//返回的主键类型为long类型,需要声明long类型接收
while (rs.next()) {//循环结果集,将得到数据赋值给实体类
keys=rs.getLong(1);
}
(4)事务的作用:
开启事务后,也就是自动提交的关闭,好处为:
例如:在新增数据时,当代码执行到
flog = ps.executeUpdate();//执行sql语句
假如没有设置开启事务,那么现在已经新增完数据,并提交不可回滚。
但之后的代码出现异常,没有返回数据,新增了多少行。因此会返回0,当返回0后,之后会用0判断新增不成功,实际上数据已经新增成功。
所以需要开启事务:
con.setAutoCommit(false);//设置自动提交为关闭,即为开启事务
开启事务后,关闭自动提交,在提交前出现异常都可以回滚。
提交con.commit();之前的代码遇到上一个提交或者开启事务,为一个事务。
最后在处理异常时执行回滚con.rollback();
con.rollback();在当前事务中删除所有更改,并释放目前由该连接对象保存的任何数据库锁。该方法仅在禁用自动提交模式时才使用。
回滚后,数据不会保存,所以返回值为0也没有关系啦。