jdbc 与 Mybatis的比较
一、原生态jdbc的不足:
1.数据库连接,使用时创建,不使用时立即释放,造成对数据库频繁的连接开启和关闭,造成数据库资源的浪费,影响数据库性能。
解:使用数据库连接池管理数据库连接。
2.将SQL语句硬编译到Java程序代码中,若修改SQL语句,则需要重新编译Java代码,不利于系统维护。
设想:将SQL语句设置到xml配置中,若SQL改变,不需要重新编译Java代码。
3.向PreparedStatement中设置参数,对占位符和设置参数值硬编译在Java代码中,SQL语句修改,则需要重新编译java代码,不利于系统维护。
设想:将SQL语句和占位符、参数全部配置在xml文件中,当修改SQL时,不需要再重新编译Java代码。
4.从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
设想:将查询的结果集,自动映射成Java对象。
中级:Servlet + JSP + JavaBean – 实现小型项目使用jdbc即可满足需求。
框架:适合中型/大型项目 – 稳定,利于扩展,利于维护,适合更多人同时访问(高并发)
二、Mybatis框架
**1.什么是Mybatis:Mybatis是一个持久型框架:可以连接操作数据库的**
(1)mybatis是一个持久框架层,是Apache下的顶级项目,最后托管到了GitHub([https://github.com/mybatis/mybatis-3/releases])
(2)mybatis让程序将主要放在SQL上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写SQL)满足需要的SQL语句。
(3)mybatis可以将preparedStatement中的输入参数自动进行输入映射,将查询的结果集映射成Java对象(输出映射)。
参数-->SQL:输入映射 SQL-->java:输出映射
**2.mybatis框架工作原理**
(1)mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。
(2)mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
(3)通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
(4)SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
(5)Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括java的简单类型、HashMap集合对象、POJO对象类型。
三、程序应用实现
1.项目要求:
(1)根据用户id(主键)查询用户信息
(2)根据用户名称模糊查询用户信息
(3)添加用户
(4)删除用户
(5)修改用户
2.环境
Java环境:JDK 1.8.0_181
Eclipse:neon
Oracle:Oracle11g
Mybatis运行环境(jar包):
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
加入oracle的驱动jar
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
需要手动添加Oracle的驱动jar:
首先进入ojdbc6.jar所在目录:D:\Oracle\product\11.2.0\dbhome_1\jdbc\lib
执行命令:mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.3 -Dpackaging=jar -Dfile=ojdbc6.jar
3. SqlMapConfig.xml
配置mabatis
<configuration>
<!-- 配置数据源、事务等mybatis运行环境 -->
<!-- 与Spring整合后将被废除 -->
<environments default="development">
<environment id="development">
<!-- 配置事务 -->
<transactionManager type="JDBC" />
<!-- 配置数据源 -->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.OracleDriver" /><!-- 驱动类 -->
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" /><!-- 连接路径 -->
<property name="username" value="user01" /><!-- 用户名 -->
<property name="password" value="654321" /><!-- 密码 -->
</dataSource>
</environment>
</environments>
<!-- 加载映射路径 -->
<mappers>
<!-- 加载单个映射配置文件 resource属性中包名使用/不是.-->
<mapper resource="com/it/mapper/UserMapper.xml"/>
</mappers>
</configuration>
4根据需求操作:用户根据用户id(主键)查询用户信息
第一步 编写实体类
public class User {
private int id;//用户编号
private String loginname;//用户名
private String password;//密码
private String realname;//真实姓名
private String sex;//性别
private String birthday;//生日
private int dep;//部门编号
private String email;//邮箱
private int enabled;//是否可用
private int createman;//创始人
private String dname;//部门名称
private String lasttime;//上次登录时间
@Override
public String toString() {
return "User [id=" + id + ", loginname=" + loginname + ", password=" + password + ", realname=" + realname
+ ", sex=" + sex + ", birthday=" + birthday + ", dep=" + dep + ", email=" + email + ", enabled="
+ enabled + ", createman=" + createman + ", dname=" + dname + ", lasttime=" + lasttime + "]";
}
public String getLasttime() {
return lasttime;
}
public void setLasttime(String lasttime) {
this.lasttime = lasttime;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLoginname() {
return loginname;
}
public void setLoginname(String loginname) {
this.loginname = loginname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRealname() {
return realname;
}
public void setRealname(String realname) {
this.realname = realname;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public int getDep() {
return dep;
}
public void setDep(int dep) {
this.dep = dep;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
this.enabled = enabled;
}
public int getCreateman() {
return createman;
}
public void setCreateman(int createman) {
this.createman = createman;
}
}
第二步 映射文件与Mapper接口对应
import java.util.List;
import com.it.bean.User;
public interface UserMapper {
/**
* 根据id查询用户信息
* */
public User selectUserById(int id);
/**
* 根据id模糊查询
* */
public List<User> selectUserByLikeName(String name);
/**
* 添加用户
* */
public int addUser(User user);
/**
* 根据id修改用户密码
* */
public int updatePassword(User user);
/**
* 根据用户信息删除用户信息
* */
public int deleteUserById(int id);
}
映射文件命名格式(建议):XXXMapper.xml,例如:UserMapper.xml;
在映射文件中配置SQL语句
<!-- 引入映射配置文件的dtd约束 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace属性:与当前映射配置文件对应的mapper接口的全路径
建议:映射配置文件和mapper接口的文件名一致,有利于区分当前映射配置文件代替了那个mapper接口的实现类
-->
<mapper namespace="com.it.mapper.UserMapper">
<!-- 根据地查询用户信息的SQL语句
select标签表示查询
id属性值:对应表示的mapper接口中的方法名
将SQL语句封装到MapperStatement的对象中,id可以理解是MapperStatement对象的id
id是唯一的
parameterType属性:表示Mapper接口中方法的参数属性,若没有可不写
resultTypes表示输出结果的类型
#{}:占位符,相当于?
#{id}:用来接收输入参数的内容
-->
<select id="selectUserById" parameterType="int" resultType="com.it.bean.User">
select * from tuser where id = #{id}
</select>
<!-- 根据用户名模糊查询用户信息
resultType属性:表示单条记录所映射的java对象类型
${}:表示将接收到的参数内容不添加任何修饰的拼接到SQL语句中
#{}与${}的区别:
1.#{}表示占位符,防止SQL注入,安全
2.${}表示拼接SQL串,不能防止SQL注入,不安全
例子:select * from tuser where loginname=#{loginname} and password=#{password}
若:loginname = adim or 1=1
select * from tuser where loginname=${loginname} and password=${password}
-->
<select id="selectUserByLikeName" parameterType="String" resultType="com.it.bean.User">
select * from tuser where loginname like '%${value}%'
</select>
<!-- 新增用户
parameterType属性中若类型为pojo对象类型,#{}中为对象的属性名
-->
<insert id="addUser" parameterType="com.it.bean.User">
<!-- selectKey表示主键的生成策略,目前用的是序列
keyProperty="id" 表示生成的主键赋值给id
resultType:表生成的主键类型
order="BEFORE":表示在插入语句前先生成主键值
-->
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select seq_tuser.nextval from dual
</selectKey>
insert into tuser values(#{id},#{loginname},#{password},#{realname},#{sex},#{birthday},#{dep},#{email},1,1,null)
</insert>
<!-- 根据id修改用户密码
-->
<update id="updatePassword" parameterType="com.it.bean.User" >
update tuser set password=#{password} where id=#{id}
</update>
<!-- 根据id删除用户 -->
<delete id="deleteUserById" parameterType="int">
delete from tuser where id=#{id}
</delete>
</mapper>
第三步 在SqlMapConfig.xml文件中加载映射文件
注意:上面已经添加过,下面只是具体展示映射文件的部分
<!-- 加载映射路径 -->
<mappers>
<!-- 加载单个映射配置文件 resource属性中包名使用/不是.-->
<mapper resource="com/it/mapper/UserMapper.xml"/>
</mappers>
第四步 代码程序测试
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import com.it.bean.User;
import com.it.mapper.UserMapper;
public class UserCrud {
@Test
public void selectById() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//调用相应的方法
User user = mapper.selectUserById(1);
System.out.println(user);
//关闭会话
session.close();
}
@Test
public void selectUsersByName() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//调用相应
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.selectUserByLikeName("a");
//查询
for(User user: users){
System.out.println(user);
}
//关闭会话
session.close();
}
/**
* 添加用户
* @throws IOException
*
* */
@Test
public void addUser() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//调用相应的方法
User user = new User();
user.setLoginname("xiaozhang");
user.setPassword("123456");
user.setSex("男");
user.setBirthday("1997-09-09");
user.setDep(2);
user.setRealname("张三");
user.setEmail("zs@163.com");
//调用新增用户的值
int result = mapper.addUser(user);
if(result>0){
System.out.println("新增成功!");
}else{
System.out.println("新增失败!");
}
//提交事务
session.commit();
//关闭会话
session.close();
}
/**
* @throws IOException
*
* */
@Test
public void updatePassword() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//调用相应的修改方法
User user = new User();
user.setId(271);
user.setPassword("654321");
//
int result = mapper.updatePassword(user);
if(result>0){
System.out.println("密码修改成功!");
}else{
System.out.println("密码修改失败!");
}
//提交事务
session.commit();
//关闭会话
session.close();
}
/**
* 根据id删除用户
* @throws IOException
* */
@Test
public void deleteUserById() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//调用相应的修改方法
User user = new User();
//
int result = mapper.deleteUserById(272);
if(result>0){
System.out.println("删除成功!");
}else{
System.out.println("删除失败!");
}
//提交事务
session.commit();
//关闭事务
session.close();
}
}
可能出现的错误:
SQL语句修改字段与数据库内的字段不符。
pom.xml配置出现问题,常见为下载jar包失败,导致无法找到相关测试文件。
初始化失败,无法找到测试文件:可能的原因有很多,常见为方法名不一致,返回值类型有误,参数列表有误等