搭建MyBatis框架见MyBatis入门
准备数据
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
age INT
);
INSERT INTO USER(id,NAME,age) VALUES(1,"Jack",22);
INSERT INTO USER(id,NAME,age) VALUES(2,"张三",20);
INSERT INTO USER(id,NAME,age) VALUES(3,"Java",23);
准备JavaBean
package cn.hncu.domain;
/*
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
age INT
);
*/
public class User {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
映射文件UserMapper.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">
<!-- 采用接口开发时,namespace的值必须是接口类的类全名
-->
<mapper namespace="cn.hncu.domain.UserMapper">
<!-- 使用接口开发,接口中的方法名必须跟id值一致 -->
<select id="all" resultType="User"> <!-- 由于mybatis中设置了别名,所以resultType可以使用别名 -->
select * from user
</select>
<!-- 单条件查询 -->
<select id="query1" parameterType="int" resultType="User">
select * from user where id=#{id}
</select>
<!-- 多条件查询 使用POJO、map、list或者QueryValueModel parameterMap已经不推荐使用 -->
<!--
select * from user where id=#{id} or name LIKE "%"#{name}"%" AC
select * from user where id=#{id} or name LIKE concat("%",#{name},"%") AC
select * from user where id=#{id} or name LIKE "%${name}%" AC
-->
<!-- 使用${}类似于EL表达式,与 #{}相比,它不会把特殊字符进行转义,有安全隐患-->
<select id="query2" parameterType="cn.hncu.domain.User" resultType="User">
select * from user where id=#{id} or name LIKE concat("%",#{name},"%")
</select>
<!-- 范围查询使用查询值对象 -->
<select id="query3" parameterType="cn.hncu.domain.UserQueryModel" resultType="User">
select *
from user
where id=#{id}
or age <![CDATA[>=]]> #{age}
and age <![CDATA[<=]]> #{age2}
</select>
<!-- 范围查询使用map封装条件 -->
<select id="query4" parameterType="map" resultType="User">
select *
from user
where id=#{id}
or age <![CDATA[>=]]> #{age}
and age <![CDATA[<=]]> #{age2}
</select>
<!-- 增 -->
<insert id="add" parameterType="User" >
insert into
user(name,age)
values(#{name},#{age})
</insert>
<!-- 删 -->
<delete id="del" parameterType="int">
delete from user where id=#{id}
</delete>
<!-- 改 -->
<update id="update" parameterType="User">
update user
set name=#{name}, age=#{age}
where id=#{id}
</update>
<!-- 下面演示使用 sql标签,作用:当一条sql重复使用时,可以使用sql标签定义,
使用时用include标签引入一下就可以了
-->
<sql id="userColumn">
id,name,age
</sql>
<select id="sqlDemo" resultType="User">
select <include refid="userColumn"/> from user
</select>
<!-- 下面演示获取自动增长id
当parameterType为值对象时,keyProperty必须与值对象中的主键属名一致
如果想要不一致可以使用 map 作为parameterType的值,读取时通过keyProperty的值作为key
-->
<insert id="autoKeys"
useGeneratedKeys="true"
keyProperty="id"
parameterType="User">
insert into
user(name,age)
values(#{name},#{age})
</insert>
<insert id="autoKeys2"
useGeneratedKeys="true"
keyProperty="iid"
parameterType="map">
insert into
user(name,age)
values(#{name},#{age})
</insert>
</mapper>
映射接口
不采用接口也是可以运行起来的,但是采用接口的方式使以后面对庞大的数据表时,面向接口编程就不用到映射文件中去查询该如何调用,接口上的注解可以很清晰的表述出来,同时通过接口还可避免一些不必要的类型强转异常。
package cn.hncu.domain;
import java.util.List;
import java.util.Map;
public interface UserMapper {
/**
* 查询所有user信息
* @return 封装所有用户信息的List
*/
public List<User> all();
/**
* 根据用户id查询相应的用户
* @param id User的id属性,主键
* @return user 或者 null
*/
public User query1(int id);
/**
* 模糊查询,按理条件查询应该使用查询值对象
* @param user 值对象
* @return 封装符合条件的用户信息的List
*/
public List<User> query2(User user);
/**
* 范围查询,使用查询值对象
* @param uqm 查询值对象
* @return 封装符合条件的用户信息的List
*/
public List<User> query3(UserQueryModel uqm);
/**
* 范围查询,使用map封装查询条件,与查询值对象相比较灵活,但是使用时需要注意key值的对应
* @param map 封装查询条件的map
* @return 封装符合条件的用户信息的List
*/
public List<User> query4(Map<String, Object> map);
/**
* 添加一条用户记录
* @param user 封装了用户信息的值对象
*/
public Integer add(User user);
/**
* 根据用户id删除相应的用户记录
* @param id 用户id,主键
*/
public Integer del(Integer id);
/**
* 修改用户信息
* @param user 新的用户信息
* @return
*/
public Integer update(User user);
public List<User> sqlDemo();
public Integer autoKeys(User user);
public Integer autoKeys2(Map<String, Object> map);
}
全局配置文件中引入映射文件
使用映射器接口实现类的完全限定类名:
<configuration>
<mappers><mapper class="cn.hncu.domain.UserMapper"/></mappers>
</configuration>
<?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>
<!-- '类型别名' 是为 Java类型设置一个短的名字。它只和 'XML配置'有关,存在的意义仅在于用来减少类完全限定名的冗余 -->
<typeAliases>
<typeAlias alias="User" type="cn.hncu.domain.User" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<!-- & 转义 -->
<property name="url" value="jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="1234" />
<!-- 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10-->
<property name="poolMaximumActiveConnections" value="5"/>
<!-- 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒) -->
<property name="poolMaximumCheckoutTime" value="30000"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mapper class="cn.hncu.domain.UserMapper"/>
<!-- 使用相对于类路径的资源引用 -->
<mapper resource="cn/hncu/domain/UserMapper2.xml"/>
</mappers>
<!--
-->
</configuration>
查询所有
注意:下面的所有演示中,User都是cn.hncu.domain.User的别名,因为在上面全局配置文件中使用了<typeAliases>进行取别名。
<!-- 使用接口开发,接口中的方法名必须跟id值一致 -->
<select id="all" resultType="User"> <!-- 由于mybatis中设置了别名,所以resultType可以使用别名 -->
select * from user
</select>
//无条件查询
@Test
public void all() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
List<User> users = userMapper.all();
for (User user : users) {
System.out.println(user);
}
}
单条件查询
<!-- 单条件查询 -->
<select id="query1" parameterType="int" resultType="User">
select * from user where id=#{id}
</select>
//单条件查询
@Test
public void query1() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
User user = userMapper.query1(1);
System.out.println( user );
}
多条件查询
POJO封装查询条件
<!-- 多条件查询 使用POJO、map、list或者QueryValueModel parameterMap已经不推荐使用 -->
<!--
select * from user where id=#{id} or name LIKE "%"#{name}"%" AC
select * from user where id=#{id} or name LIKE concat("%",#{name},"%") AC
select * from user where id=#{id} or name LIKE "%${name}%" AC
-->
<!-- 使用${}类似于EL表达式,与 #{}相比,它不会把特殊字符进行转义,有安全隐患-->
<select id="query2" parameterType="cn.hncu.domain.User" resultType="User">
select * from user where id=#{id} or name LIKE concat("%",#{name},"%")
</select>
//多条件查询
@Test
public void query2() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
User user = new User();
user.setId(1);
/*
select * from user where id=#{id} or name LIKE '%${name}%'
user.setName("j%' or 1=1 or name ='"); //BUG
select * from user where id=#{id} or name LIKE "%${name}%"
user.setName("j%\" or 1=1 or name =\""); //BUG
*/
user.setName("j%\" or 1=1 or name =\"");
//user.setName("j");
List<User> users = userMapper.query2(user);
for (User u : users) {
System.out.println(u);
}
}
查询值对象封装查询条件
查询值对象:继承User,专用于封装查询条件的JavaBean。
package cn.hncu.domain;
public class UserQueryModel extends User {
private Integer age2;
public Integer getAge2() {
return age2;
}
public void setAge2(Integer age2) {
this.age2 = age2;
}
}
ORM映射
<!-- 范围查询使用查询值对象 -->
<select id="query3" parameterType="cn.hncu.domain.UserQueryModel" resultType="User">
select *
from user
where id=#{id}
or age <![CDATA[>=]]> #{age}
and age <![CDATA[<=]]> #{age2}
</select>
测试
//使用查询值对象
@Test
public void query3() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
UserQueryModel uqm = new UserQueryModel();
uqm.setId(1);
uqm.setAge(20);
uqm.setAge2(22);
List<User> users = userMapper.query3(uqm);
for (User u : users) {
System.out.println(u);
}
}
添加
<!-- 增 -->
<insert id="add" parameterType="User" >
insert into
user(name,age)
values(#{name},#{age})
</insert>
//增
@Test
public void add() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
User user = new User();
user.setName("刘备");
user.setAge(19);
userMapper.add(user);
//注意:增删改都必须commit
sqlSession.commit(); //提交事务
all(); //调用查询所有
}
添加并获取自动增长ID
<!-- 下面演示获取自动增长id
当parameterType为值对象时,keyProperty必须与值对象中的主键属名一致
如果想要不一致可以使用 map 作为parameterType的值,读取时通过keyProperty的值作为key
-->
<insert id="autoKeys"
useGeneratedKeys="true"
keyProperty="id"
parameterType="User">
insert into
user(name,age)
values(#{name},#{age})
</insert>
//演示获取自动增长id---值对象封装
@Test
public void autoKeys() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
User user = new User();
user.setName("麻花藤");
user.setAge(38);
userMapper.autoKeys(user);
System.out.println(user);//User [id=7, name=马化腾, age=38]
sqlSession.commit();
}
删除
<!-- 删 -->
<delete id="del" parameterType="int">
delete from user where id=#{id}
</delete>
//删
@Test
public void del() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
userMapper.del(3);
sqlSession.commit(); //提交事务
all(); //调用查询所有
}
修改
<!-- 改 -->
<update id="update" parameterType="User">
update user
set name=#{name}, age=#{age}
where id=#{id}
</update>
//改
@Test
public void update() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
User user = new User();
user.setName("老干妈");
user.setAge(18);
user.setId(4);
userMapper.update(user);
//注意:增删改都必须commit
sqlSession.commit(); //提交事务
all(); //调用查询所有
}