Mybatis - 简单使用Mybatis 实现 增删改查

时间:2021-10-25 17:00:17

1.传统的JDBC实现

   首先我们先看下传统的JDBC的代码 :


public class JdbcDemo {

private final static String CONN_URL="jdbc:oracle:thin:@localhost:1521:xe";
private final static String ORACLE_DRIVER="oracle.jdbc.OracleDriver";
private final static String CONN_NAME="hr";
private final static String CONN_PASSWORD="hr";

public static void main(String[] args) throws Exception {

Class.forName(ORACLE_DRIVER);
Connection conn = DriverManager.getConnection(CONN_URL, CONN_NAME, CONN_PASSWORD);
String sql="select * from f_client";
PreparedStatement psm = conn.prepareStatement(sql);
// psm.setInt(1, 14);
ResultSet rs = psm.executeQuery();
while(rs.next()){
System.out.println(rs.getString("username")+" :"+rs.getString("now_address"));
}
rs.close();
psm.close();
conn.close();
}
}

      在这里我们使用的是Oracle数据库,使用通过SQL语句操作数据库 ,会发现以下问题 :

    (1)数据库连接,使用时创建,不使用立即释放,对数据库频繁的连接开启和关闭,造成数据库资源浪费,影响数据库性能;
       解决:使用数据库连接池来解决;
  (2)将sql语句硬编码到java代码中,如果sql语句修改,需要重新编译java代码,不利于系统维护。
       解决:将sql语句配置在xml配置文件中,就不需要编译源代码了。
  (3)向preparedStatement中设置参数.对占位符位置和设置参数值,硬编码在java代码中,不利于维护;
       解决:将sql语句及占位符和参数全部配置在xml中;
  (4)从resutSet中遍历结果集数据时,存在硬编码,不利于维护;
       解决:将结果自动映射为java对象;


2.Mybatis的一些名词及其作用

   mybatis是持久层的框架,是apache下的*项目,可以github中clone;

   mybatis将主要精力放在sql上,通过mybatis提供的映射方式,*的灵活生成(半自动化,大部分的程序需要的sql)满足的sql语句;
   mybatis可以将向preparedStatementa中输入参数自动进行输入映射,将查询结果集灵活的映射为java对象(输出映射);   
    
   SqlMapConfig.xml 是mybatis的全局配置文件,配置了数据源,事务等mybatis运行环境,配置映射文件(sql语句)mapper.xml...;
   
   SqlSessionFactory 会话工厂,作用:创建SqlSession;根据配置文件创建工厂
   
   SqlSession 会话 ,作用 :操作数据库,发出sql的增删改查;是接口
   
   Executor 执行器 ,作用 :sqlSession内部通过执行器操作数据库;是接口(基本执行器,缓存执行器)
   
   mapped statement 底层封装对象,作用 :对操作数据库存储封装,包括sql语句,输入参数,输出结果类型;
   
   数据输入输出的参数类型:值类型,hashmap ,pojo自定义。


3.实例 - 实现对客户信息的增删改查

        注意里面的所出现的名词,查看 2里面的相关名词 及其解释 ,mybatis实例代码在文章最后,包含里面的jar包均有(JDBC - Oracle数据库驱动)。

    (1)创建员工表和添加数据

           创建F_Client 客户表 :

CREATE TABLE F_CLIENT(
ID NUMBER(12) PRIMARY KEY,--用户编号
USERNAME VARCHAR2(20) NOT NULL,--用户姓名
CLIENT_CERTIFICATE_NO VARCHAR2(20) NOT NULL UNIQUE,--证件号码
BORN_DATE DATE,--出生日期
FAMILY_REGISTER_ADDRESS VARCHAR2(200),--家庭住址
NOW_ADDRESS VARCHAR2(200) NOT NULL,--现在住址
CONTACT_MODE VARCHAR2(50) NOT NULL,--联系方式
URGENCY_CONTACT_MODE VARCHAR2(50) NOT NULL,--紧急联系方式
CREATE_DATE DATE NOT NULL--创建时间
);

         添加4条数据 :

     

insert into F_CLIENT (ID, USERNAME, CLIENT_CERTIFICATE_NO, BORN_DATE, FAMILY_REGISTER_ADDRESS, NOW_ADDRESS, CONTACT_MODE, URGENCY_CONTACT_MODE, CREATE_DATE)
values (1, 'sawyer', '1593224056', to_date('10-10-1980', 'dd-mm-yyyy'), '北京市海淀区东北旺', 'peaking', '123456789', '987654321', to_date('15-12-2015 08:47:13', 'dd-mm-yyyy hh24:mi:ss'));

insert into F_CLIENT (ID, USERNAME, CLIENT_CERTIFICATE_NO, BORN_DATE, FAMILY_REGISTER_ADDRESS, NOW_ADDRESS, CONTACT_MODE, URGENCY_CONTACT_MODE, CREATE_DATE)
values (2, 'yangly', '1593224057', to_date('11-10-1980', 'dd-mm-yyyy'), '北京市海淀区东北旺', 'peaking', '123456789', '987654321', to_date('15-12-2015 08:47:13', 'dd-mm-yyyy hh24:mi:ss'));

insert into F_CLIENT (ID, USERNAME, CLIENT_CERTIFICATE_NO, BORN_DATE, FAMILY_REGISTER_ADDRESS, NOW_ADDRESS, CONTACT_MODE, URGENCY_CONTACT_MODE, CREATE_DATE)
values (3, 'gaozhy', '1593224058', to_date('12-12-1980', 'dd-mm-yyyy'), '湖北省洪山区黄家湖', 'shanghai', '123456789', '987654321', to_date('15-12-2015 08:47:13', 'dd-mm-yyyy hh24:mi:ss'));

insert into F_CLIENT (ID, USERNAME, CLIENT_CERTIFICATE_NO, BORN_DATE, FAMILY_REGISTER_ADDRESS, NOW_ADDRESS, CONTACT_MODE, URGENCY_CONTACT_MODE, CREATE_DATE)
values (4, 'wangmj', '1593224059', to_date('13-04-1980', 'dd-mm-yyyy'), '湖北省洪山区黄家湖', 'hubei', '123456789', '987654321', to_date('15-12-2015 08:47:13', 'dd-mm-yyyy hh24:mi:ss'));

   (2)配置Log4j DEBUG

            新建Log4j.properties 文件

# Global logging configuration
# 开发的时候配置为 DEBUG
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

 

    (3)配置SqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
        <!--临时配置的数据库访问数据-->	<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:xe" />				<property name="username" value="hr" />				<property name="password" value="hr" />			</dataSource>		</environment>	</environments>
        <!--配置mapper-->	<mappers>		<mapper resource="sqlmap/Client.xml" />	</mappers></configuration>

  (4)实现客户表操作的mapper 

          1)注意namespace ,sql操作标签id,需要使用

          2)sql 语句不需要 分号 (;)

          3)parameterType 参数类型

          4)resultType 返回结果类型


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 -->
<!-- 注意:使用mapper代理的方法开发,namespace有特殊的重要作用 -->

<mapper namespace="test">

<!-- 在映射文件中配置很多的sql语句 -->
<!-- 通过select 执行数据库查询 id:表示映射文件的sql, 将sql语句封装到mappedStatement对象中,所以将id称为statement的id
#{}: 表示一个占位符,相当于jdbc中的? parameterType : 指定参数类型,比如指定为int #{id} : 其中的id表示接入输入的参数,参数名称就是id,如果输入的参数是简单类型
#{}中参数名可以任意,可以value或其他名称; resultType :指定sql输出的结果的映射java对象类型,select指定的resultType表示将单条记录映射成java对象 -->
<!-- 根据id查用户 -->
<select id="findClientById" parameterType="int" resultType="mybatis.po.FClient">
select * from f_client where id=#{id}
</select>

<!-- 根据用户名模糊查询 resultType :指定的单条记录所映射的java对象类型 #{} 表示占位符 ${}:表示拼接sql串,将接收到的参数内容不加任何修饰拼接在sql中,使用${}拼接,引起sql注入
${value} :接入输入参数的内容,如果传入类型是简单类型,${}简单的 -->
<select id="findClientByName" parameterType="java.lang.String"
resultType="mybatis.po.FClient">
select *from f_client where username like '%${value}%'
</select>

<!-- 添加用户 这里注意 主键返回实现 -->
<select id="insertClient" parameterType="mybatis.po.FClient"
resultType="java.lang.Integer">
insert into
f_client(id,username,client_certificate_no,born_date,family_register_address,now_address,contact_mode,urgency_contact_mode,create_date)
values (#{id},
#{username},#{client_certificate_no},#{born_date},#{family_register_address},#{now_address},#{contact_mode},#{urgency_contact_mode},#{create_data})
</select>

<!-- 删除用户 -->
<delete id="deleteClient" parameterType="int">
delete from f_client where id=#{id}
</delete>

<!-- 更新用户 -->
<update id="updateClient" parameterType="mybatis.po.FClient">

update f_client set
username=#{username},client_certificate_no=#{client_certificate_no},born_date=#{born_date},family_register_address=#{family_register_address},now_address=#{now_address},contact_mode=#{contact_mode},urgency_contact_mode=#{urgency_contact_mode}
where id=#{id}

</update>


</mapper>




      命名: Client.xml(原始的) , mapper代理开发映射文件名称叫做xxxmapper.xml;
    作用: 在映射文件中配置sql语句
namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离;
注意:使用mapper代理的方法开发,namespace有特殊的重要作用;
paramterType : 在映射文件中通过指定参数类型
resultType :输出结果类型
#{} 表示一个占位符
${} 表示一个拼接符号,会引起sql注入,不建议使用;
selectOne 表示查询出一条记录进行映射
selectList 表示查询出一个列表(多条记录)进行映射


   (5)实现客户表的Pojo 

package mybatis.po;

import java.util.Date;


/**
*
* 用户po
* 作者:原明卓
* 时间:2015年12月17日 下午2:58:18
* 描述:TODO
*/
public class FClient {
@Override
public String toString() {
return "FClient [id=" + id + ", username=" + username
+ ", client_certificate_no=" + client_certificate_no
+ ", born_date=" + born_date + ", family_register_address="
+ family_register_address + ", now_address=" + now_address
+ ", contact_mode=" + contact_mode + ", urgency_contact_mode="
+ urgency_contact_mode + ", create_data=" + create_data + "]";
}
//属性名和数据库名对应
private Integer id;
private String username;
private String client_certificate_no;
private Date born_date;
private String family_register_address;
private String now_address;
private String contact_mode;
private String urgency_contact_mode;
private Date create_data;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getClient_certificate_no() {
return client_certificate_no;
}
public void setClient_certificate_no(String client_certificate_no) {
this.client_certificate_no = client_certificate_no;
}
public Date getBorn_date() {
return born_date;
}
public void setBorn_date(Date born_date) {
this.born_date = born_date;
}
public String getFamily_register_address() {
return family_register_address;
}
public void setFamily_register_address(String family_register_address) {
this.family_register_address = family_register_address;
}
public String getNow_address() {
return now_address;
}
public void setNow_address(String now_address) {
this.now_address = now_address;
}
public String getContact_mode() {
return contact_mode;
}
public void setContact_mode(String contact_mode) {
this.contact_mode = contact_mode;
}
public String getUrgency_contact_mode() {
return urgency_contact_mode;
}
public void setUrgency_contact_mode(String urgency_contact_mode) {
this.urgency_contact_mode = urgency_contact_mode;
}
public Date getCreate_data() {
return create_data;
}
public void setCreate_data(Date create_data) {
this.create_data = create_data;
}

}


  (6)实现操作方法

           1)使用Resources.getResourceAsStream(sqlmapconfig.xml) 加载数据库配置

           2)创建会话工厂 :参入为mybatis的配置文件信息

           3)通过工厂得到SqlSession

           4)通过sqkSession操作数据库 ,第一个参数:映射文件中statement的id等于=namespace+"."+statement的id,结果与ResultType 的结果集一样

           5)释放资源


package mybatis.frist;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

import mybatis.po.FClient;

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;

/**
* 测试Mybatis
*
* 作者:原明卓 时间:2015年12月17日 下午4:37:25 描述:TODO
*/
public class TestMyBatis {

// 根据id查询用户信息,得到一条记录结果
@Test
public void findClientByIdTest() {
String resource = "SqlMapConfig.xml";

InputStream is;
SqlSession os = null;
try {
is = Resources.getResourceAsStream(resource);
// 创建会话工厂 :参入为mybatis的配置文件信息
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

// 通过工厂得到SqlSession
os = build.openSession();

// 通过sqkSession操作数据库
// 第一个参数:映射文件中statement的id等于=namespace+"."+statement的id
// 结果与ResultType 的结果集一样
FClient client = os.selectOne("test.findClientById", 14);

System.out.println(client);

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
// 释放资源
os.close();
}
}
}

/**
* 根据用户姓名模糊查询
*/
@Test
public void findClientByNameTest() {
String resource = "SqlMapConfig.xml";

InputStream is;
SqlSession os = null;
try {
is = Resources.getResourceAsStream(resource);
// 创建会话工厂 :参入为mybatis的配置文件信息
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

// 通过工厂得到SqlSession
os = build.openSession();

// 通过sqkSession操作数据库
// 第一个参数:映射文件中statement的id等于=namespace+"."+statement的id
// 结果与ResultType 的结果集一样
List<FClient> clients = os
.selectList("test.findClientByName", "ya");

System.out.println(clients);

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
// 释放资源
os.close();
}
}
}

/**
* 添加用户信息
*/
@Test
public void addClient() {
String resource = "SqlMapConfig.xml";

InputStream is;
SqlSession os = null;
try {
is = Resources.getResourceAsStream(resource);
// 创建会话工厂 :参入为mybatis的配置文件信息
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

// 通过工厂得到SqlSession
os = build.openSession();

// 通过sqkSession操作数据库
// 第一个参数:映射文件中statement的id等于=namespace+"."+statement的id
// 结果与ResultType 的结果集一样
FClient c = new FClient();
c.setId(5);
c.setBorn_date(new Date());
c.setClient_certificate_no("我是新增的");
c.setContact_mode("我是新增的");
c.setCreate_data(new Date());
c.setFamily_register_address("我是新增的");
c.setNow_address("我是新增的");
c.setUrgency_contact_mode("我是新增的");
c.setUsername("yuha");

int row = os.insert("test.insertClient", c);
System.out.println(row);
// 提交事务
os.commit();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
// 释放资源
os.close();
}
}

}

@Test
public void deleteClient() {
String resource = "SqlMapConfig.xml";

InputStream is;
SqlSession os = null;
try {
is = Resources.getResourceAsStream(resource);
// 创建会话工厂 :参入为mybatis的配置文件信息
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

// 通过工厂得到SqlSession
os = build.openSession();

// 通过sqkSession操作数据库
// 第一个参数:映射文件中statement的id等于=namespace+"."+statement的id
// 结果与ResultType 的结果集一样

os.delete("test.deleteClient",15);
os.commit();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
// 释放资源
os.close();
}
}

}


@Test
public void updateClient() {
String resource = "SqlMapConfig.xml";

InputStream is;
SqlSession os = null;
try {
is = Resources.getResourceAsStream(resource);
// 创建会话工厂 :参入为mybatis的配置文件信息
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

// 通过工厂得到SqlSession
os = build.openSession();

// 通过sqkSession操作数据库
// 第一个参数:映射文件中statement的id等于=namespace+"."+statement的id
// 结果与ResultType 的结果集一样

FClient c = new FClient();
c.setId(4);
c.setBorn_date(new Date());
c.setClient_certificate_no("我是修改的1");
c.setContact_mode("我是修改的");
c.setCreate_data(new Date());
c.setFamily_register_address("我是修改增的");
c.setNow_address("我是修改的");
c.setUrgency_contact_mode("我是修改的");
c.setUsername("yuha");

os.update("test.updateClient", c);
// 提交事务
os.commit();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
// 释放资源
os.close();
}
}

}

}

    (6)实现主键返回 

             在client.xml 的mapper中实现 :

    主键返回 : 
mysql: 自增主键返回 使用函数 LAST_INSERT_ID() ,相对于insert语句,在其后执行
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Intger">
<!--
插入数据,返回主键id. 返回到keyProperty(为 parameterType的某个属性里)
order :执行的顺序,相对于insert 语句来说的执行顺序
-->
Select LAST_INSERT_ID()
</selectKey>
非自增主键,使用uuid()函数生成主键,相对于insert语句,在其后执行
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Intger">
<!--
插入数据,返回主键id. 返回到keyProperty(为 parameterType的某个属性里)
order :执行的顺序,相对于insert 语句来说的执行顺序
-->
Select UUID()
</selectKey>

Oracel : 使用序列实现,和mysql非自增主键相似;



4.mybatis和hibernate 本质区别和应用场景

 ( 1)hibernate 是一个标准的ORM(对象关系映射)框架,入门门槛高,不需要写sql,sql自动生成,对sql语句进行优化,修改比较困难;
     应用场景 : 适应与需求变化不多的中小型项目,比如:后台管理系统;
  
 ( 2)mybatis 专注的是sql本身,需要自己编写sql语句,sql修改,优化比较方便,一个不完全的orm框架,虽然自己写sql , 也可以实现映射(输入输出映射);
     应用场景 :适应与需求变化较多的项目,比如 :互联网项目;

5.Demo 免积分下载

http://download.csdn.net/detail/lablenet/9369787