Maven创建Mybatis工程
1.mybatis概述
1.1 框架
框架是软件开发过程中的一套解决方案,不同框架解决不同问题,框架封装了很多细节,可以使开发者用极简的方式来实现项目。
三层架构与MVC设计模式目标一致,都是为了解耦合并提高代码复用,但是二者对于项目的理解角度不同。三层分别为:表示层(USL,User Show Layer:视图层)、业务逻辑层(BLL,Business Logic Layer:Service层)、数据访问层(DAL,Data Access Layer:Dao层)。上层依赖于下层(持有成员变量或需要有下层才能成立)

数据访问层技术包含:JDBC、Spring的JdbcTemplate(Spring中对jdbc的简单封装)、Apache的DBUtils。但这些都不是框架,JDBC属于规范,而Spring或Apache对应的内容都只是工具类。而MyBatis则属于数据访问层框架。(后续要说的Spring MVC 属于表示层框架),JDBC的内容可以参考之前的文章。其中的demo如下:
import java.sql.*;
public class JDBCDemo {
static final String URL="jdbc:oracle:thin:@localhost:1521:ORC";
static final String USERNAME="scott";
static final String PWD="tiger";
public static void update(){//增删改
//a.导入驱动,加载具体的驱动类
Connection connection=null;
Statement stmt=null;
ResultSet resultSet=null;
try{
Class.forName("oracle.jdbc.OracleDriver");
//b.与数据库建立连接
connection=DriverManager.getConnection(URL,USERNAME,PWD);
//c.发送sql并执行
// (1)Statement方式
stmt=connection.createStatement();
String sql="insert into Users values('zhangsan',18)";
String query="select age,name from Users";
resultSet=stmt.executeQuery(query);//resultSet为指向行的数据,.getXXX()获取对应类型数据
int count=stmt.executeUpdate(sql);//执行增删改,返回值表示增删改了几条
// (2)PrepareStatement方式(sql语句提前,可用?替代值),推荐使用此方法
//在多运行条件下,sql编译一次,数据被执行N次。而Statement方式方式sql也需要被执行N次
//此方式可以防止sql注入
String sql2="insert into Users values(?,?)";
PreparedStatement pstmt=connection.prepareStatement(sql2);//预编译
pstmt.setString(1,"zhangsan");//set方法替换占位符
pstmt.setInt(1,18);
int count2=pstmt.executeUpdate();
//(3)CallableSatatement方式(调用存储过程(无返回值,out代替)或存储函数(有返回值))
//(?,?,?)前两个参数相加,第三个参数为输出参数,输出两个的和
CallableStatement cstmt=connection.prepareCall("call addTwoNum(?,?,?)");
cstmt.setInt(1,10);//set处理参数
cstmt.setInt(2,10);
cstmt.execute();
//设置输出参数的类型
cstmt.registerOutParameter(3,Types.INTEGER);
int result=cstmt.getInt(3);
//d.处理结果
if(count>0){
System.out.println("操作成功");
}
while(resultSet.next()){//next表示下移,判断下移之后是否有元素,有则为true,否则为false
int age=resultSet.getInt("age");
String name=resultSet.getString("name");
//上面两行数据等价于如下两行,此对应编号从1开始,但推荐使用字段名而不是下标查询
//int age=resultSet.getInt(1);
//String name=resultSet.getString(2);
System.out.println(name+""+age);
}
}
catch(ClassNotFoundException | SQLException e){
e.printStackTrace();
}
finally{
try{
if(resultSet!=null) resultSet.close();
if(stmt!=null)stmt.close();//对象.方法,如果对象为空会报空指针
if(connection!=null) connection.close();
//先开的后关,后开的先关
}
catch (SQLException e){
e.printStackTrace();
}
}
}
public static void main(String[] args){
update();
}
}
MyBatis基于java,采用了ORM(Object Relational Mapping对象关系映射)的思想,解决了实体和数据库映射的问题(如User类对应数据库的user表),对JDBC进行了封装,屏蔽了JDBC API底层访问细节。开发者只需要关注SQL语句,不需要再去写JDBC中加载驱动、创建连接、Statement等过程。MyBatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终的sql语句。
1.2 环境搭建与demo
创建Maven工程,接着创建实体类和dao接口,然后创建Mybatis的主配置文件(sqlMapConfig.xml),再创建映射文件(IUserDao.xml)在其中写增删改查等语句。最后写测试类,session.selectOne("需要查询的nmaespace.id","SQL参数值")
Maven工程,在IDEA创建新工程的方式选择maven,然后配置生成的pom.xml,内容如下。本文Mybatis工程连接的数据库是mysql, maven会根据<dependency>标签中的内容帮我们下载相应驱动。不用maven连接mysql数据库可以参考之前的文章进行对比。关于Maven的简单介绍及用法请见文章末尾。
//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>02_10</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!-- 使用mybatis用上述两个配置即可-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
</project>
(1)创建实体类User和对应接口IUserDao
在java文件夹下创建User、IUserDao代码如下
//IUserDao.java
package org.example.dao;
import org.example.domain.User;
import java.util.List;
//用户的数据访问层接口
public interface IUserDao {
//查询所有操作
List<User> findAll();
}
//User.java
package org.example.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
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 Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
(2)配置Mybatis
//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="mysql">
<!-- 配置mysql环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/javaweb"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<mappers>
<mapper resource="org/example/dao/IUserDao.xml"/>
</mappers>
</configuration>
MyBatis的映射配置文件位置必须和IUserDao一致,并且其mapper标签和namespace属性的取值要和Dao接口的全限定类名一致<mapper namespace="org.example.dao.IUserDao">
根据我们的项目所运行环境的不同,如本机、发布环境等,可以<environment id="mysql">
通过id值不同进行不同配置,然后通过<environments default="mysql">
default值去调用对应的id,选取相应的运行环境。运行环境的选取也可以在测试文件的SqlSessionFactoryBuilder().build(reader,"mysql");
语句中指定。
transactionManager 事务提交方式除了用JDBC方式(commit、rollback、close),还可以用MANAGED,这个是将事务交由其他组件去托管(如,Spring),MANAGED在默认方式下会关闭连接。如果不想关闭需配置语句<property name="closeConnection" value="false"/>
dataSource的数据类型,除了demo中写的
<dataSource type="POOLED">
POOLED代表使用数据库连接池,type还可以是UNPOOLED,
这个就是传统的JDBC模式,每次都需要打开、关闭数据库等。但是这种操作较为消耗性能。还可以是JNDI方式,这个是从tomcat中获取一个内置的数据库连接池(POOLED是第三方的,非tomcat自带)。一般dataSource用POOLED。
(3)在resources文件夹下创建IUserDao.xml(Mapper),和IUserDao接口二者名称相对应。
//IUserDao.xml
<?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">
<mapper namespace="org.example.dao.IUserDao">
<!--配置查询所有-->
<!-- id为Dao中的方法名称-->
<!-- 此Dao一般也命名为Mapper-->
<select id="findAll" resultType="org.example.domain.User" parameterType="int">
select * from TestUsers
</select>
</mapper>
namespace是该mapper.xml映射文件的唯一标识,在其他文件中定位此处sql的sql语句就用namespace.id的方式。parameterType
代表输入参数类型,resultType
代表查询返回结果类型。MyBatis理论上只接收一个传入值并只输出一个值,如果想变成多个值,需要把其换成类或对象的形式。
映射配置文件的操作配置(如select),其id属性的取值必须是Dao接口的方法名。
如果要往sql语句中传入sql,可以通过#{}。如果传入参数时简单类型(8个基本类型+String)那么可以使用任何形式占位符#{XXX},但如果是对象类型,则括号中必须是对象的属性#{属性名}。输出参数如果返回的是一个对象,无论是一个还是多个值,resultTyoe都是全限定类名。
<select id="findAll" resultType="org.example.domain.User" parameterType="int">
select * from TestUsers where id=#{id}
</select>
增删改的方式如下:
<insert id="add" parameterType="org.example.domain.User">
insert into TestUsers(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
<update id="update" parameterType="org.example.domain.User">
update TestUsers set id=#{id},username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
<delete id="deletebyid" parameterType="int">
delete from TestUsers where id=#{id}
</delete>
(4)建立测试文件MybatisTest
在test文件夹的java文件夹下,建立对应的测试文件夹结构org.example.test,目录下简历测试文件MybatisTest.java,其代码内容如下。
package org.example.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.*;
import org.example.domain.User;
import java.io.IOException;
import java.io.Reader;
public class MybatisTest {
public static void main(String[] args) throws IOException {
//1.读取配置文件
Reader reader= Resources.getResourceAsReader("SqlMapConfig.xml");
//2.创建SqlSessionFactor工厂
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
//3.使用工厂生产SqlSession对象并创建Dao接口的代理对象
//session=JDBC的connection
SqlSession session=sqlSessionFactory.openSession();
//4.使用代理对象执行方法
String statement="org.example.dao.IUserDao.findAll";
User person = session.selectOne(statement);
System.out.println(person);
//5.释放资源
session.close();
}
}
完成后直接run即可看到运行图如下,成功从数据库中取出内容。如果需要往sql语句中传值,在执行方法时可以写成User person = session.selectOne(statement,1);
,此处的1即为id=1

如果是增删改,前三个步骤都不变,第四步骤使用代理对象执行方法改变部分如下:
//增
String statement="org.example.dao.IUserDao.add";
Date date=new Date();
User users=new User(3,"wangwu",date,"男","黑龙江漠河");
int count = session.insert(statement,users);
session.commit();
//删
String statement="org.example.dao.IUserDao.deletebyid";
int count =session.delete(statement,3);
session.commit();
System.out.println("删除了"+count+"个学生");
//改
String statement="org.example.dao.IUserDao.update";
Date date=new Date();
User user=new User();
user.setId(3);
user.setUsername("dududu");
user.setBirthday(date);
user.setSex("男");
user.setAddress("黑龙江漠河");
int count =session.update(statement,user);
session.commit();
1.3 Mapper动态代理方式(MyBatis接口开发)
配置方式在.xml中定义,硬编码是在.java中的定义。约定则是默认值。动态代理原则就是约定优于配置。与上节不同的是,动态代理方式约定的目标,可以省略掉statement,即根据约定直接定位出SQL语句。
既然是基于接口开发,首先要定义一个接口。接口的方法和IUserDao.xml(mapper)中SQL标签一一对应,且namespace的值是接口的全类名。
以删除为例,其Mapper文件如下
//IUserDao.java
public interface IUserDao {
int deletebyid(int id);
}
注意,此处方法名和IUserDao.xml(mapper)文件中标签的id值相同,并且方法的输入参数和标签的parameterType类型一致,方法的输出参数(返回值)和标签resultType一致
<delete id="deletebyid" parameterType="int">
delete from TestUsers where id=#{id}
</delete>
相应的在测试文件MybatisTest.java中将delUsers()函数原来为//后内容,改为接口形式如下:
//MybatisTest.java
// String statement="org.example.dao.IUserDao.deletebyid";
// int count =session.delete(statement,3);
IUserDao user= session.getMapper(IUserDao.class);
int count=user.deletebyid(3);
1.4 配置文件优化
(1)动态引入
SqlMapConfig.xml中数据库配置相关内容如下:
//SqlMapConfig.xml
<configuration>
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/javaweb?characterEncoding=gbk"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</<configuration>
如果我们想动态的加载相应信息,可以创建一个db.properties放入配置文件,让SqlMapConfig.xml去调用此文件,从而动态引入。其文件内容如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/javaweb?characterEncoding=gbk
username=root
password=
SqlMapConfig.xml相应内容如下,是键值对的形式。
//SqlMapConfig.xml
<configuration>
<properties resource="db.properties"/>
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</<configuration>>
(2)全局参数
全局参数采用的标签是
//SqlMapConfig.xml
<settings>
<setting name="cacheEnabled" value="false" />
</settings>
(3)别名
<typeAliases>
<!-- 单个别名(忽略大小写)-->
<typeAlias type="org.example.domain.User" alias="User"/>
<!-- 多个别名(别名就是不带包名的类名,忽略大小写)-->
<package name="org.example.domain"/>
</typeAliases>
2.Maven
2.1 Maven简介
Maven 翻译为"专家"、"内行",是 Apache 下的一个纯 Java 开发的开源项目。Maven 是一个项目管理工具,可以对 Java 项目进行构建、依赖管理。也可应用于其他语言编写的项目,例如 C#,Ruby,Scala等。Maven是基于Java的自动化构建工具,说到自动化建构工具,按照发展历程讲有make、ant、Maven、Gradle等。Maven则是现在的主流。Maven的作用包括:管理Jar包,将项目拆分成若干个模块等。以管理jar文件为例,Maven可以增加第三方Jar,如commons-fileupload.jar ,commons-io.jar。也可以管理jar包之间的依赖关系,当我们导入一个包的时候,其他所需的依赖,Maven会自动关联下载。
2.2 Maven生命周期
Maven的构建(build)生命周期,从验证(validate)->编译(compile)->测试(Test)->包装(package)->检查(verify)->安装(install)->部署(deploy)
(1)验证
验证项目是否正确且所有必须信息是可用的
(2)编译
java->class
(3)测试
针对项目中的关键点进行测试,也可用项目中的测试代码去测试开发代码。使用适当的单元测试框架(例如JUnit)运行测试。将测试的结果以报告形式进行显示。
(4)包装
将项目中包含的多个文件压缩成一个文件,用于安装或部署(java项目—jar,web项目-war)
(5)检查
对集成测试的结果进行检查,以保证质量达标
(6)安装
将达成的包放到本地仓库供其他项目使用
(7)部署
拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。
所以当我们执行其中的某个命令时,会把前面相应的步骤执行一遍。
除了上述的构建周期(default lifecycle),还有清理周期(clean lifecycle:pre-clean、clean、post-clean)和站点周期(site lifecycle:pre-site、site、post-site、site-deploy)。清理用于删除编译的结果,为重新编译做准备。采用命令mvn post-clean
执行。
2.3 Maven的目录结构

pom.xml配置的关键内容如下
<groupId>大项目名</groupId>
<groupId>com.jsoft.test</groupId>
<artifactId>子模块名</artifactId>
<artifactId>HelloWorld</artifactId>
<version>版本号</version>
<version>0.1-SNAPSHOT</version>
所有执行mvn的命令,必须在pom.xml所在目录中执行
maven常见命令如下:
mvn compile(只编译Main目录中的java文件)
mvn test (测试)
mvn package(打成jar/war)
mvn install(将开发的模块放入本地仓库)
mvn clean(删除target目录)
2.4 Maven仓库
首先要了解依赖的含义,加入common-fileupload.jar
依赖于commons-io.jar
即A中的某些类需要使用B中的某些类,就称为A依赖于B。Maven中如果要使用存在的jar或模块就可以通过依赖实现,去本地仓库或者中央仓库寻找。
仓库,是项目中依赖的第三方库所在的位置。在Maven中,任何一个依赖、插件或者项目构建的输出都可以称之为构件。而仓库就可以帮我们管理这些构件(主要是JAR),它就是放置所有JAR文件(WAR,ZIP,POM等等)的地方。Maven 仓库有三种类型:本地(local)、中央(central)、远程(remote)。本地仓库在第一次执行maven命令的时候被创建,maven所需的任何构件都是直接从本地仓库获取,如果本地没有,就尝试从远程仓库下载到本地仓库,然后再使用。Maven 中央仓库是由 Maven 社区提供的仓库,其中包含了大量常用的库。如果 Maven 在中央仓库中也找不到依赖的文件,它会停止构建过程并输出错误信息到控制台。为避免这种情况,Maven 提供了远程仓库的概念,它是开发人员自己定制仓库,包含了所需要的代码库或者其他工程中用到的 jar 文件。
