三、MyBatis增删改查
3.1 新增
1、持久层接口添加方法
void addUser(User user);
2、映射文件添加标签
<insert id="addUser" parameterType="com.zj.pojo.User"> INSERT INTO user VALUES (default ,#{username},#{sex},#{address}) </insert>
3、编写测试方法
@Test public void TestAddUser() throws IOException { /*建造者*/ SqlSessionFactoryBuilder SQLSessionFactoryBuilder = new SqlSessionFactoryBuilder(); /*建造者根据配置文件建造工厂*/ InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory = SQLSessionFactoryBuilder.build(resourceAsStream); /*工厂生产SqlSession*/ SqlSession sqlSession = factory.openSession(); /*SqlSession获取接口的代理对象*/ UserMapper mapper = sqlSession.getMapper(UserMapper.class); /*代理对象调用方法*/ mapper.addUser(new User(0,"ddd","男","上海")); /*提交事务*/ sqlSession.commit(); /*释放资源*/ sqlSession.close(); resourceAsStream.close(); }
注意:
- 当接口方法的参数类型为POJO类型时,SQL语句中绑定参数时使用
#{POJO的属性名}
即可。- MyBatis事务默认手动提交,所以在执行完增删改方法后,需要手动调用SqlSession对象的事务提交方法,否则数据库将不发生改变。
3.2 修改
优化测试类
import com.zj.mapper.UserMapper; import com.zj.pojo.User; 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.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class TestUserMapper { InputStream resourceAsStream = null; SqlSession sqlSession = null; UserMapper mapper =null; /*优化*/ @Before public void getSqlSession() throws IOException { /*配置文件*/ resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); /*建造者*/ SqlSessionFactoryBuilder SQLSessionFactoryBuilder = new SqlSessionFactoryBuilder(); /*建造者根据配置文件创建工厂*/ SqlSessionFactory factory = SQLSessionFactoryBuilder.build(resourceAsStream); /*工厂生产SqlSession*/ sqlSession = factory.openSession(); /*SqlSession获取代理对象*/ mapper = sqlSession.getMapper(UserMapper.class); } @Test public void TestSelectAllUser() throws IOException { List<User> users = mapper.selectAllUser(); for (User user : users) { System.out.println(user); } } @Test public void TestAddUser() throws IOException { /*代理对象调用方法*/ mapper.addUser(new User(0,"ddd","男","上海")); /*提交事务*/ sqlSession.commit(); } @After public void close() throws IOException { sqlSession.close(); resourceAsStream.close(); } }
1、持久层接口添加方法
void updateUser(User user);
2、映射文件添加标签
<update id="updateUser" parameterType="com.zj.pojo.User"> UPDATE user SET username = #{username}, sex = #{sex},address = #{address} WHERE id = #{id} </update>
3、编写测试方法
@Test public void TestUpdateUser(){ mapper.updateUser(new User(7,"哈哈哈","女","青岛市")); /*提交事务*/ sqlSession.commit(); }
3.3 根据id删除
1、持久层接口添加方法
/*根据id删除*/ void removeUser(int id);
2、映射文件添加标签
<delete id="removeUser" parameterType="int"> DELETE FROM user WHERE id = #{id} </delete>
注:当方法的参数类型是简单数据类型时,#{}中可以写任意名称
- 简单数据类型:基本数据类型、字符串等
3、编写测试方法
@Test public void TestRemoveUser(){ mapper.removeUser(7); /*提交事务*/ sqlSession.commit(); }
3.4 模糊查询
1、持久层接口添加方法
/*模糊查询*/ List<User> getUserLikeName(String userName);
2、映射文件添加标签
<select id="getUserLikeName" parameterType="string" resultType="com.zj.pojo.User"> SELECT * FROM user WHERE username like #{username} </select>
模糊查询如果不想在调用方法时参数加%,可以使用拼接参数的方式设置Sql:
<select id="getUserLikeName" parameterType="string" resultType="com.zj.pojo.User"> SELECT * FROM user WHERE username like '%${value}%' </select>
如果使用#
还不想在调用方法的参数中添加%
,可以使用<bind>
,<bind>
允许我们在 Sql语句以外创建一个变量,并可以将其绑定到当前的Sql语句中。既能防止sql注入还能在传递参数的时候不需要传递百分号。用法如下:
<select id="getUserLikeName" parameterType="string" resultType="com.zj.pojo.User"> <bind name="likeName" value="'%'+username+'%'"/> SELECT * FROM user WHERE username like #{likeName} </select>
#和$的区别:
- #表示sql模板的占位符,$表示将字符串拼接到sql模板中。
- #可以防止sql注入,一般能用#就不用$。
- ${}内部的参数名必须写value。
我们看到在映射文件中,parameterType的值为
string
而没有写java.lang.String
,这是为什么呢?
- 参数/返回值类型为基本数据类型/包装类/String等类型时,我们可以写全类名,也可以写别名。
3、编写测试方法
/*模糊查询*/ @Test public void TestGetUserLikeName(){ List<User> users = mapper.getUserLikeName("%三%"); for (User user : users) { System.out.println(user); }
如果使用sql拼接、或者是<bind>的话直接写参数就行了:
/*模糊查询*/ @Test public void TestGetUserLikeName(){ List<User> users = mapper.getUserLikeName("三"); for (User user : users) { System.out.println(user); } }
3.5 分页查询
分页查询时,Sql语句使用limit关键字,需要传入开始索引和每页条数两个参数。MyBatis的多参数处理有以下方式:
顺序传参
Sql中的参数使用arg0,arg1...或param1,param2...表示参数的顺序。此方法可读性较低,在开发中不建议使用。
@Param传参
在接口方法的参数列表中通过@Param定义参数名称,在Sql语句中通过注解中所定义的参数名称指定参数位置。此方式参数比较直观的,推荐使用。
1、持久层接口方法
/*分页查询*/ List<User> getUserByPage(@Param("start") int start, @Param("size") int size);
2、映射文件
<!--分页查询--> <select id="getUserByPage" resultType="com.zj.pojo.User"> SELECT * FROM user LIMIT #{start},#{size} </select>
3、测试类
/*分页查询*/ @Test public void TestGetUserByPage(){ List<User> users = mapper.getUserByPage(0, 3); for (User user : users) { System.out.println(user); } }
POJO传参
自定义POJO类,该类的属性就是要传递的参数,在SQL语句中绑定参数时使用POJO的属性名作为参数名即可。此方式推荐使用。
1、自定义POJO
public class PageQuery { private int startIndex; private int pageSize; // 省略getter/setter/构造方法 }
2、持久层接口方法
/*分页查询2*/ List<User> getUserByPage2(PageQuery pageQuery);
3、映射文件
<!--分页查询2--> <select id="getUserByPage2" resultType="com.zj.pojo.User"> SELECT * FROM user LIMIT #{startIndex},#{pageSize} </select>
4、测试类
/*分页查询2*/ @Test public void TestGetUserByPage2(){ List<User> userByPage2 = mapper.getUserByPage2(new PageQuery(0, 3)); for (User user : userByPage2) { System.out.println(user); } }
Map传参
如果不想自定义POJO,可以使用Map作为传递参数的载体,在SQL语句中绑定参数时使用Map的Key作为参数名即可。此方法推荐使用。
1、持久层接口方法
/*分页查询3*/ List<User> getUserByPage3(Map<String,Object> params);
2、映射文件
<!--分页查询3--> <select id="getUserByPage3" resultType="com.zj.pojo.User" parameterType="map"> SELECT * FROM user LIMIT #{start},#{size} </select>
3、测试类
/*分页查询3*/ @Test public void TestGetUserByPage3(){ Map<String, Object> map = new HashMap<>(); map.put("start",0); map.put("size",3); List<User> userByPage3 = mapper.getUserByPage3(map); for (User user : userByPage3) { System.out.println(user); } }
3.6 聚合查询和主键回填
查询用户总数
1、持久层方法
int findCount();
2、映射文件
<!--查询总数--> <select id="findCount" resultType="int"> select count(id) from user; </select>
3、测试
/*查询总数*/ @Test public void TestGFindCount(){ int count = mapper.findCount(); System.out.println(count); }
主键回填
有时我们需要获取新插入数据的主键值。如果数据库中主键是自增的,这时我们就需要使用MyBatis的主键回填功能。
1、持久层方法
/*主键回填*/ void addUser2 (User user);
2、映射文件
<!--主键回填--> <insert id="addUser2" parameterType="com.zj.pojo.User" > /*keyProperty:主键属性名称 keyColumn:主键列名 resultType:主键类型 order:执行时机,插入之后执行*/ <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID(); </selectKey> INSERT INTO user VALUES (default ,#{username},#{sex},#{address}) </insert>
SELECT LAST_INSERT_ID():查询刚刚插入的记录的主键值,只适用于自增主键,且必须和insert语句一起执行。
3、测试
/*主键回填*/ @Test public void TestAddUser2(){ User user = new User(0,"啊张","男","海口市"); mapper.addUser2(user); /*提交*/ sqlSession.commit(); /*获取回填的id*/ int id = user.getId(); System.out.println(id);//9 }