能够完成单表的CRUD操作
掌握mybatis框架的输入输出映射
掌握mybatis框架在Dao层的开发
掌握sqlMapConfig.xml中常用标签(properties、typeAliases、mappers)
实现用户表(user)的增、删、改、查操作。
根据用户Id查询用户
根据用户名称模糊查询用户
新增用户
根据用户Id修改用户
根据用户Id删除用户
mybatis框架包
数据库驱动包
log4j日志包
junit单元测试包
<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.0modelVersion>
<groupId>TestgroupId>
<artifactId>mybatis_crudartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<mybatis.version>3.4.5mybatis.version>
<mysql.version>5.1.30mysql.version>
<slf4j.version>1.7.7slf4j.version>
<log4j.version>1.2.17log4j.version>
<junit.version>4.12junit.version>
properties>
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>${mybatis.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
dependency>
dependencies>
project>
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# 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
package com.po;
public class User {
private int id;
private String username;
private String birthday;
private String sex;
private String address;
public User() {
}
public User(int id, String username, String birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String 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 + '\'' +
'}';
}
}
package com.dao;
import com.po.User;
import java.util.List;
public interface UserDao {
List<User> findAll();
List<User> findByName(String username);
int insert(User user);
int update(User user);
int delete(int id);
}
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/zzw?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="dao/map/UserDaoMap.xml"/>
mappers>
configuration>
mybatis框架针对数据库操作:新增/修改/删除/查询,提供了对应的标签: insert/update/delete/select标签放置
根据用户Id查询用户,说明:
select标签:放置查询sql语句
id:唯一标识名称,与接口方法名称一致
parameterType:输入参数类型,与接口方法形参类型一致
resultType:返回值类型(暂时注意:它是po类的全限定名称),与接口方法返回值类型一致
#{id}:占位符,相当于jdbc中的问号
<select id="findByName" resultType="com.po.User" parameterType="string">
select * from user where username like "%${value}%"
select>
1.占位符 | #{} | 当参数传递的是java简单类型(八种基本类型+字符串String)的时候,花括号中的内容可以是任意字符串 |
---|---|---|
2.字符串拼接符 | ${} | 当参数传递的是java简单类型(八种基本类型+字符串String)的时候,花括号中的内容只能是value |
3. | #{}、${} | 当参数传递的pojo类型的时候,花括号中的内容都是pojo的属性 |
<mapper namespace="com.dao.UserDao">
<select id="findAll" resultType="com.po.User">
select * FROM user
select>
<select id="findByName" resultType="com.po.User" parameterType="string">
select * from user where username like #{username}
select>
<insert id="insert" parameterType="com.po.User">
insert into user value (null ,#{username},#{birthday},#{sex},#{address})
insert>
<update id="update" parameterType="com.po.User">
update user set username = #{username},birthday=#{birthday} ,sex=#{sex},address=#{address} where id=#{id}
update>
<delete id="delete" parameterType="int">
delete from user where id= #{int}
delete>
mapper>
注意事项:java程序代码执行成功,但是数据库中并没有新增记录。原因是没有提交事务,在对数据库的更新操作中(增、删、改)要求提交事务。
/**
* 手动提交事务
*/
sqlSession.commit();
/**
* 创建SqlSession,指定自动提交事务。true:自动提交;false:不提交。默认是false
*/
SqlSession sqlSession = sqlSessionFactory.openSession(true);
说明:自动提交的特点,只要操作一完成,立即提交。如果在同一个方法中,有多个数据库操作,需要使用手动提交的方式。
import com.dao.UserDao;
import com.po.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class App {
@Test
public void testFindAll() {
InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void testfindByName() {
InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> users = userDao.findByName("王");
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void testInsert() throws Exception {
InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder sqlsessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = sqlsessionFactoryBuilder.build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = new User();
user.setUsername("xxx");
user.setBirthday("2018-08-08");
user.setAddress("广州");
user.setSex("男");
int insert = userDao.insert(user);
System.out.println(insert);
sqlSession.commit();
sqlSession.close();
resourceAsStream.close();
}
@Test
public void testUpdate() throws Exception {
InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = new User();
user.setId(50);
user.setUsername("xxx");
user.setBirthday("2008-08-08");
user.setAddress("广州");
user.setSex("男");
int i = userDao.update(user);
System.out.println(i);
sqlSession.commit();
sqlSession.close();
resourceAsStream.close();
}
@Test
public void testDelete() throws Exception {
InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
int i = userDao.delete(50);
System.out.println(i);
sqlSession.commit();
sqlSession.close();
resourceAsStream.close();
}
}
说明:当数据库表中,主键字段值由数据库维护(比如mysql中的自增长),则不需要我们传递。那么在新增完一条记录以后,如何获取到数据库维护的主键值呢?
<mapper namespace="com.dao.UserDao">
<insert id="insert" parameterType="com.po.User">
<selectKey resultType="int" order="AFTER" keyColumn="id" keyProperty="id">
select LAST_INSERT_ID()
selectKey>
insert into user (username,birthday,sex,address)value (#{username},#{birthday},#{sex},#{address})
insert>
mapper>
思考:什么时候使用BEFORE?
答案:oracle数据库。
<insert id="insertUser" parameterType="cn.itheima.po.User">
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="BEFORE">
select seq.nextval from dual
selectKey>
insert into `user`(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
insert>
<insert id="addUser" parameterType="cn.po.User"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into `user`(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
insert>
说明:直接在insert标签中增加属性的方式,只适合于支持自动增长主键类型的数据库,比如mysql。
参考:
<delete id="delete" parameterType="int">
delete from user where id= #{int}
delete>
参考:
<insert id="insert" parameterType="com.po.User">
insert into user value (null ,#{username},#{birthday},#{sex},#{address})
insert>
定义:pojo包装类型,就是在pojo中包含了其它的pojo。通常用于接收综合查询条件。
使用pojo包装类型,实现根据用户名称模糊查询用户。
package com.po;
public class QueryPo {
private User user;
public QueryPo() {
}
public QueryPo(User user) {
this.user = user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "QueryPo{" +
"user=" + user +
'}';
}
}
List<User> findByName(QueryPo queryPo);
<select id="findByName" resultType="com.po.User" parameterType="com.po.QueryPo">
select * from user where username like #{user.username}
select>
@Test
public void testfindByName() throws Exception{
InputStream resourceAsStream = App.class.getResourceAsStream("/SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user1 = new User();
user1.setUsername("%王%");
QueryPo queryPo = new QueryPo(user1);
List<User> users = userDao.findByName(queryPo);
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
resourceAsStream.close();
}
<select id="acount" resultType="int">
select count(*) from user
select>
参考:
<select id="findAll" resultType="com.po.User">
select * from user
select>
查询全部数据封装到User2对象中。
package com.po;
public class User2 {
//num对应的数据库字段是id
private int num;
private String username;
//shengri对应的数据库字段是birthday
private String shengri;
private String sex;
private String address;
public User2() {
}
public User2(int num, String username, String shengri, String sex, String address) {
this.num = num;
this.username = username;
this.shengri = shengri;
this.sex = sex;
this.address = address;
}
public int getnum() {
return num;
}
public void setnum(int num) {
this.num = num;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getshengri() {
return shengri;
}
public void setshengri(String shengri) {
this.shengri = shengri;
}
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{" +
"num=" + num +
", username='" + username + '\'' +
", shengri='" + shengri + '\'' +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
List<User2> finAllUser2();
<resultMap id="user2map" type="com.po.User2">
<id property="num" column="id"/>
<result property="username" column="username"/>
<result property="shengri" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
resultMap>
<select id="finAllUser2" resultMap="user2map">
select * from user
select>
@Test
public void testfinAllUser2() throws Exception {
InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User2> user2s = userDao.finAllUser2();
for (User2 user2 : user2s) {
System.out.println(user2);
}
sqlSession.close();
resourceAsStream.close();
}
从入门程序开始,一直使用的方式,即mapper代理开发的方法。特点:
在开发的时候,只需要编写持久层的接口,和持久层接口映射文件(mapper映射文件)。
在执行的时候,mybatis框架通过动态代理生成接口的代理对象。
mapper映射文件中namespace属性值,必须是mapper接口的全限定名称
mapper映射文件中sql语句标签的声明,与mapper接口中接口方法声明一致
2.1.sql语句标签中resultType属性指定的返回值类型,与mapper接口方法返回值类型一致。(如果接口方法返回的是集合list,则resultType指定的是list中存放的类型)
2.2.sql语句标签中的id属性值,与mapper接口方法名称一致
2.3.sql语句标签中的parameterType属性指定的类型,与mapper接口方法的形参类型一致
根据用户Id查询用户
新增一个用户
<mapper namespace="test">
<select id="findUserById" parameterType="int" resultType="po.User">
select * from `user` where id=#{id}
select>
<insert id="addUser" parameterType="po.User"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into `user`(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
insert>
mapper>
package mapper;
import po.User;
/**
* 用户dao接口
*/
public interface UserDao {
/**
* 1.根据用户Id查询用户
*/
User findUserById(Integer id);
/**
* 2.新增用户
*/
void insertUser(User user);
}
package mapper.impl;
import mapper.UserDao;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import po.User;
import util.SqlSessionFactoryUtil;
/**
* 用户dao实现类
*/
public class UserDaoImpl implements UserDao {
/**
* 1.根据用户Id查询用户
*
* @param id
*/
public User findUserById(Integer id) {
// 1.获取sqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.调用方法执行
/**
* selectOne方法:查询单条记录
* 参数:
* statement:执行的sql语句(名称空间+"."+sql语句id)
* parameter:传入的参数值
*/
Object user = sqlSession.selectOne("test.findUserById", id);
// 4.释放资源
sqlSession.close();
return (User) user;
}
/**
* 2.新增用户
*
* @param user
*/
public void insertUser(User user) {
// 1.获取sqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3.调用方法执行
/**
* insert方法:新增记录
* 参数:
* statement:执行的sql语句(名称空间+"."+sql语句id)
* parameter:传入的参数值
*/
sqlSession.insert("test.addUser", user);
// 4.释放资源
sqlSession.close();
}
}
<mappers>
<mapper resource="sqlmap/UserMapper.xml">mapper>
<mapper resource="sqlmap/OrdersMapper.xml">mapper>
<mapper resource="sqlmap/User.xml">mapper>
mappers>
package test;
import mapper.UserDao;
import mapper.impl.UserDaoImpl;
import org.junit.Test;
import po.User;
/**
* 传统的dao开发方法测试
*/
public class UserDaoTest {
/**
* 测试根据用户Id查询用户
*/
@Test
public void findUserByIdTest() {
// 1.创建dao实现类对象
UserDao userDao = new UserDaoImpl();
User user = userDao.findUserById(24);
System.out.println(user);
}
}
测试新增用户:
/**
* 测试新增用户
*/
@Test
public void addUserTest(){
// 1.创建dao实现类对象
UserDao userDao = new UserDaoImpl();
// 创建用户对象
User user = new User();
user.setUsername("阿飞");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("天下第一快剑");
userDao.insertUser(user);
}
sqlMapConfig.xml是mybatis框架的核心配置文件,目前我们在其中配置了运行环境(数据源)和加载映射文件。该配置文件中还有其它的一些配置。
顺序 | 配置标签名称 | 说明 |
---|---|---|
1 | properties | 属性 |
2 | settings | 配置全局参数 |
3 | typeAliases | 类型别名 |
4 | typeHandlers | 类型处理器 |
5 | objectFactory | 对象工厂 |
6 | plugins | 插件 |
7 | environments | 环境集合属性对象 |
8 | databaseIdProvider | 多数据库支持 |
9 | mappers | 映射器 |
说明:在sqlMapConfig.xml中必须是从上往下的配置顺序
作用:加载属性资源文件和定义属性。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/zzw?characterEncoding=utf8
jdbc.username=root
jdbc.password=root
<properties resource="jdbc.properties"/>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
environment>
environments>
加载顺序:首先加载内部property标签定义属性,再加载属性资源文件中的属性。如果有相同的属性,属性资源文件中的属性会覆盖内部property标签定义的属性。
属性资源文件优先
<properties resource="db.properties">
<property name="db.username" value="root">property>
<property name="db.password" value="admin">property>
properties>
作用:简称。比如中华人民共和国,简称中国。
别名 | 映射类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
说明:
内置别名可以直接使用
别名不区分大小写
<typeAliases>
<typeAlias type="cn.po.User" alias="user"/>
typeAliases>
<typeAliases>
<package name="com.po"/>
typeAliases>
作用:加载映射文件。
<mappers>
<mapper resource="sqlmap/UserMapper.xml">mapper>
<mapper resource="sqlmap/OrdersMapper.xml">mapper>
<mapper resource="sqlmap/User.xml">mapper>
mappers>
要求mapper映射文件的名称和路径地址,要与mapper接口的名称和路径地址要一致,否则会出现BindingException异常。
<mappers>
<package name="com.dao" />
mappers>