Spring Data JPA Pagination

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up friends dan vega here back with another tutorial and today we're talking about pagination in spring data jpa before we get started though in case this is the first time you're coming across one of my videos my name is dan vega i'm a spring developer advocate for vmware tonzu i also run the website danvega.dev if you want to head over there you're going to get a whole bunch of free stuff i have a blog i have a newsletter i love to write what we're going to go off of today is actually a blog post i just published and this is an entire blog post dedicated to what we're going to cover in today's tutorial so if you're more of a let me just read through a blog post first then watch the video type of person this is great for you again head over to my website learn a bunch about me get a whole bunch of free content with that let's get started with today's tutorial so i'm just going to talk through a little bit of the blog post and then we'll push it aside again you could read this on your own pace and i'll go through basically these steps in a video form but what we're talking about is pagination with spring data jpa if you have just a few records you could create a a an endpoint in a rest api a graphql whatever and you can just return of the records in the real world though you'll probably have more than a few records you know thousands hundreds of hundreds of thousands in this case you wouldn't want to return all of those records at once that would be a huge performance hit and you wouldn't want to do that no matter what device you're on so on the client you just want to display a small number of records that allows the user to kind of say next next previous or click on a particular page number so that's what we're going to build today and we're going to have walk through each of the steps to go ahead and do so this is in part part one of a larger tutorial that i worked on this week for both spring data rest our spring data jpa pagination and then the graphql side of things so stay tuned if you're interested in some graphql content um that is coming up real quickly so with that what you're going to do is follow the guide here and the first thing that i'm going to do is head over to start.spring.io real quickly in that blog post there's a link to the github repository again this is it says spring for graphql paging don't worry the graphql stuff is kind of in the background the spring data gpa paging is front and center and that's really what we're going to cover today all right so i'm going to close that i'm going to get rid of my face here and let's go through this tutorial together all right so we're going to start here over at start that spring.io and we're going to create a new project this is the spring initializer allows us to kind of bootstrap a spring boot project so we got to make some decisions here uh the first is maven or gradle really just use whatever you're comfortable with uh i've been using maven forever so i'm gonna use maven again same thing with the language choose whatever language you're comfortable with i'm going to use java here the version is really up to you i'm going to use the latest stable 2.6.7 in the screenshot in the blog post i'm actually using 2.7 rc1 because again this was a two-parter as a bigger part of a spring for graphql tutorial that i was working on so that's why i had selected that but we're just going to call this um we're going to go with the group of dev.dan vega we're going to give it a name again we'll just let's just go with uh jpa paging demo project for spring boot uh the package name uh you actually have to go ahead and get rid of that which is fine let's just call it that we're gonna use packaging of jar and we're gonna use java 17. so now we need to decide what dependencies we're going to use we're actually going to build a web layer of this so that you can see it from a rest api standpoint we'll build a controller out so you can see you know how we can get all of the records and then how we can work with paging so i'm going to go ahead and choose spring web i'm also going to need spring data jpa so we'll go ahead and select that and then we'll need a database i like using h2 for just these demos again you can see that it's a fast in-memory database that supports jdbc api as well as r2 dbc so if you're using reactive that will work but here's the important part it's a small footprint and all you got to do is add this dependency and you get a database and you don't have to like set up and configure anything so this is great so we're going to do is we're going to go ahead and generate this project and open it up in whatever text editor or ide you like i'm going to open it up in intellij and we'll get started all right so the first thing i'm going to do is just open up this palm.xml you can see that we are using java 17 here is that group id and that artifact id that we put in we are we have included spring boot starter data jpa so this gives us a whole bunch of spring data info our spring data dependencies uh we've included spring boot starter web so we get webmvc we get an embedded tomcat etc and then we have this h2 database that we can use for our database in our application the first thing i like to do is just go ahead and run this application i just want to make sure everything starts up normally before i go ahead and start adding to it and it does so the first thing that our tutorial says is that we should head over to resources and application.properties and we should go ahead and add a few properties so i'm going to copy those from the blog post and paste them in here and let's just talk through these so this first thing that we're doing here is we're adding the data source name so the data source name is just going to be people we're going to be building out a little bit of a contrived example here this is a crm that's going to hold a person entity and an address entity so we're just talking about storing people and their addresses so that is why i have named it people so we're using the h2 database we want to enable the console this just allows us to go to a specific url and view the contents of our database with that data source with h2 here we have this property that says hey i'm going to go ahead and generate a unique name and that unique name gets generated every time and we don't want that we want a name that we've defined here so the default for this is true i'm going to set this to false and then i'm actually just going to turn on the show sql feature of jpa so as we're doing things it'll get logged to the console and we can see that things are happening so the next thing that we're going to do is we want to start creating you know the heart of any database application is the model like what are we modeling our application after and as i just said we're going to create a bit of a crm where we have a person and a address so the first class that i'm going to create is a person class and i'm going to go ahead and mark this as an entity again we're working with spring data jpa this isn't a jpa 101 tutorial if you're interested in me putting something like that together i'd be happy to let me know there's plenty of info out there on gpa so you can go ahead and look at that if you want to stop and work on that before you kind of go through this but what we are doing is we are marking this class as an entity and we're going to go ahead and define some fields on this the first one is an integer called id and this is actually complaining right now because hey that person should have a primary key and we're going to we're going to mark this as a primary key here and we don't want to set this so we're going to have hibernate go ahead and generate that value each time so with that now we can go ahead and add some more properties i'm going to say i need a string of first name i need a string of last name i need a string for phone number and i also need a string of email and finally i'm going to need an address uh called address i don't know why well i have i know why i have automatic imports turned on in intellij in it this is the only address it can find let's fix that and create a new address over here again we're gonna go ahead and mark this with at entity and i'm gonna go ahead and let's see we're gonna need a private we're gonna use an integer id so this will be the same as last time we need an at id and we need an at generated value and then i'm just going to create a few properties here we're going to create a no arg constructor and i'm also going to have a constructor for everything but the id i'm going to generate getters and setters and i know this questions probably coming up in your head can we use a record here dan we cannot not with jpa because records are immutable i know it stinks i wish i could i love records it makes everything so much cleaner and quicker but this wasn't that bad to use the ide to generate all this stuff now if you're using spring data jdbc you can use records with that so go ahead and check out spring data jwc if you're interested okay so now with that we can get rid of this annoying import and provide our own um why is it not letting me all right let's see there we go all right so we're going to go through this fun again where we generate a noir constructor where we generate a constructor that takes everything but that this is still complaining oh we need to fix that we will let's go ahead and add a getter and setter and finally a two string okay so now this is complaining because we have to make the association so when it comes to jpa this is really the toughest part is understanding the relationships between properties so this address is the address that we have created here but it is basically saying that hey you need to define a relationship here and so what we're going to do is say that this is a one-to-one so each person has one address while one address belongs to one person we're also going to go ahead and say that i want you to cascade type all i also want to go ahead and set the join column so i just want to say that we want to store the address id so this is going to be the reference to the address id and it's going to reference the column name id over in the address table right so that is really all we need when it comes to spring data and spring data gpa so we have our entities created the next thing we need to do is we need a way to read and persist data from our database this is where spring data really shines kind of giving us that functionality to perform most of the common operations right out of the box and what i really love is that this is really a consistent programming model across all of the spring data projects so as i mentioned before there's spring data jdbc and spring data jpa no matter which one we're using we have these repositories that we can use and then whether you're using webmvc or webflux reactive you know we have repositories for that as well so what i want to do is i'm going to create a new package here we're going to call this repository and i'm going to create a new java class called person repository and in here oh and i already messed up i got ahead of myself so we are going to create an interface called personal repository that's right interface so this interface alone isn't going to do much but the real power comes in when we go ahead and extend one of the spring data repositories so let's look at these um i listed these out in a blog post but the ones that we have available to us are repository um so this is um [Music] did i grab the wrong one yeah sorry so extends repository this is the one we want and so if you look at repository uh there really is nothing in here this is not giving us any functionality but there are reasons that you would want to use this one maybe you wanted to not make all the uh functionality that's available in say the crud repository or the paging and sorting repository you wouldn't want to make all that available maybe you just want to make a re-read-only type of repository that'd be a good place to start there's also the crud repository so the crud repository contains all of the crud methods that we might want to do in our application like save a new person or find all people or find a particular person by their id or delete them update etc so this is all that crud work that we would have normally have to write on our own that is all given to us for free finally lastly the last one i want to look at is the paging and sorting repository so each of these if you saw have two arguments first is the type so the type of repository we're building here and in our case we're working off the person entity and then in that type what is the id of the person so you remember when we set that up that was actually an integer so defining those two things here is really all you have to do now what happens when spring when the application starts up spring can see that you've extended this paging and sorting repository and we'll go ahead and make an implementation at runtime so let's look at this paging and sorting repository so first thing you want to look at is it extends the crud repository so if we want all of the functionality for building out a crud app we get it from the paging and sorting repository because it extends that but the paging and sorting repository also gives us a couple of methods for as you guessed paging and sorting so we'll come back to that in a minute but this is all we need to get started with paging and sorting so now what we need is we need a way to go ahead and add some data when the application starts so one way we could do this is we can go into the resource folder here and we could create some sql by hand but who wants to write sql by hand i don't know about you but i do not i'd much rather write some java code and add some new records to the database that way so one way that you can achieve this is by implementing a couple different interfaces in spring one is called the command line runner and one is called the application runner both allow you to execute some code after the application context is created and right before this spring application.run method has executed if you're interested in learning more about the command line runner i updated an article on my website you can go ahead and check it out it just talks a little bit more about the command line runner and why the heck you might want to use it so what we're going to do is we're going to create a new package here we're going to call this data and what i'm going to do is create a new class i'm going to call this sample data loader and this is going to go ahead and implement the command line runner and because we're implementing that command line runner actually let's jump into it and take a look at it so this is a functional interface because there is a single method in here and that method is called run so if we are going to implement that interface we need to go ahead and implement that method so let's implement run now i will take a little bit of a side tangent that i talked about in the command line runner article you may see some people go ahead and do this right in the main application class and that is because the main application class is at the end of the day a configuration class so in a configuration class whether it's this one or one that you create on your own that will go ahead and scan for beans so if you can define beans in here and so you could just say hey give me a command line runner call this command line runner this is now a opportunity to use a lambda here so we're going to say args and inside of here you could just say something like uh command line runner so then if you go ahead and run this application [Music] you should see this in the console and we do so great um now that we have that i don't want to do it here i just wanted to show you that it was possible there i actually want a class because i'm going to do some things in here now if we were to run this and do that same thing in here loading sample data if we were to run this our main application class right now nothing would actually work that's because we have to tell spring about this class it had it has no idea this class exists we can do so by marking it with the act component annotation again that's one of those stereotype annotations that just says hey spring please go ahead and manage this class for us so with that we would get the same effect but now what we want to do is i'm going to go ahead and just copy some code in here actually let's just write it out together so am going to get in a final person repository we're going to call this repository we will use constructor injection in here um i'm also going to get a logger we'll call this loggerloggerfactory.getlogger and this is the sampledataloader [Music] and that is that so now i can just say okay so now that i have an in instance of the repository we could say repository.save and we can save off an entity right so this will allow us to go ahead and save an entity and the way that we're going to do that is i'm going to create a instance of a person i'm going to copy this right from the blog post so now i have an instance of a person first name last name phone email address and address and no i do not want that one and then i can just pass in this person instance and now what happens is because this is marked with that component and because we implement the command line runner this run method is going to get called and this code is going to get executed and we're going to save some information in the database so let's see if that happens you can see down here we've actually inserted two rows one into the address database and one into the person database and again that is due to the way that we set this up we told hibernate to cascade so we've created a new person we have a new address in here so basically hibernate knows hey i need to go ahead and persist both of these records down and then it's going to create that relationship in that table for us so let's head back over to the browser and take a look at the h2 console all right so we're going to load up the correct url this is in memory and the name of the data source is people the username is essay and there is no password so i'm going to connect click on person and click run and you can see that we have our one person row in here with the column address underscore id that references address number two so let's clear this out click on address and we see address number two has streets it's street city state and zip all right let's head back over to the code all right so while this is going to work it's going to take us a long time to get enough sample data in our database to properly test out pagination like i want hundreds of records and i'm not going to do this by hand so what we are going to do is we are going to turn to a library called java faker and java faker is really great because it's a nice library that allows you to generate fake data so here is the github repo for it to get this into your project we just need to go ahead and add the dependencies so i'm using maven i'm going to grab this dependency and then there's a bunch of instructions in here i actually did a video tutorial on java faker as well so i'll go ahead and link to that in the description as well let's go ahead and open up palm.xml we're going to add that dependency we're going to reload our maven changes we're going to stop that and now we're going to head back over to here so in here is where i want to kind of save off a lot of data the first thing that i need is an instance of that faker so one thing i can do if i wanted to i'm going to go ahead and add private final faker baker um i need to say this dot faker is equal to new faker so this will work just fine this is the only place i'm using it so that's okay if i was going to use it multiple multiple places and even in the final code this is what i did i would come in here and create a bean and i would say faker faker and return new faker right so now this is going to be a bean in the application context spring is managing this for me which means that i don't need to do this i can say hey go ahead and add a constructor parameter and now spring will auto wire in that instance of faker for me so just um you know just a simple quick note on that okay so now that we have faker now what i want to do is create a whole bunch of sample data so let's create 100 rows of people in the database so how do we do that one way we can do that is we can use this int stream so i'm going to use in stream and i'm going to say give me a range closed so range closed and i'm going to start at 1 and end at 100 and as i'm doing that i'm going to map to an object so i'm going to map to an object and i'm going to map to a new person nope not that one there we go so once i map each one of these rows to a new person i want to go ahead and use the two list so you used to have to do like this you have to say collect and then use the collectors.2 list and as of recent we now can just say hey i want to go ahead and turn this into a list now the reason i want to turn this into a list is because now that once i have a list of 100 persons or people as we like to call them we can use our repository and save all you'll see the save all takes an iterable we can go ahead and pass our list of people into there so now we can go ahead and save all of those hundred people at once so this works but we need to start creating our people so inside a person remember the person constructor takes the first name last name phone number email and address so let's use faker to insert some fake data so i'm going to call faker i'm going to call name which has a whole bunch of so if we call look at name here this actually returns a name object which has things like full name first name last name etc so i'm going to choose the first name faker.name.com so the one thing that with faker and i think i mentioned this in the tutorial uh you got to look at the docs and you got to look at these different what these objects are returning because like phone number doesn't return a string so i need to get an actual phone number a string out of there so i'm going to grab cell phone the there is nothing called email address there is an internet so again if you jump in here and look at internet it returns an internet object that has a whole bunch of things like safe email addresses email addresses domains urls avatars images passwords so all the things on the internet you might need so from internet i'm going to say give me an email address and now i need a new address so inside of address i'm going to call faker.address address returns an address and it has all the things that you might need in an address so again very handy library that lets you get some like real data to work with so i'm going to say address dot city speaker.address.state speaker.address.zip and that should be it so again we're going to use an in-stream run from 1 to 100 map each of those to an object which is going to be a person object and then we use our faker library to go ahead and generate some fake data once we have this list of 100 people we call save all so this should save a hundred people in the database so let's go ahead and run this and hopefully no errors we saw a bunch of logging there which is good so let's head back over to the h2 council and if we take a look at our person table we have 100 records in here and again this is great this is actual like real data not real data but actual data that we can work with so if we wanted to do some like filtering and sorting we could so we have all these records in here if we clear this out we have addresses in here as well again just some nice data that we can use to work with okay so with that in play we have all the data in our application that we need let's talk about paging so to get started on the web side of things i'm going to create a new package called controller inside controller i'm going to create a new controller called the person controller so inside the person controller we're going to make this a rest controller we're going to respond to a request mapping of slash api people and in here we're going to create just one mapping but let's hold off on that for a second so the first thing i need is actually an instance of our person repository so i'm going to just call this repository and then we'll go ahead and add a constructor parameter and now that i have the repository i can go ahead and create a method that will accomplish what we want to do but before we do i want to look at this person repository one more time so this person repository extends paging and sorting repository and there's a method in here called find all that returns or that accepts an argument of type pageable of type pageable is an interface so we actually need an implementation of this interface to work with so there is something in spring called the page request and if we look at page request that extends the abstract page request which which also implements pageable so that is the exact class or implementation that we're looking for in this class there are some nice static helper methods called of so we can say pagerequest.of give it a page and give it a size and this is exactly what we are looking for this will return a page request which will in turn satisfy this argument type because of everything that's happening behind the scenes right so that will allow us to get exactly what we're looking for so we're going to create a get mapping here we're going to create a public the marker for that return type was a page so we'll see what page is in a second page of persons and then we'll call this find all so we're going to take two request parameters in here we need the page which is the page that you're on so it starts at zero you can have say ten records per page but when we're on page zero we're going to have records one through ten when we get to page one we're now talking about records 11 through 20. so we're going to start with a page and then a request parameter for the size so how many records per page do you want to display so we just looked at that page request before we're going to use that we'll call it a pr and then we're going to use that static method in there called of so pagerequest.of and now it's going to take in a there's there's a bunch of overloaded methods here the one that we care about just takes in a page and a size so we have those as arguments in our method so we're just going to pass those along and now that we have that page requests we can go ahead and return the repository.find all and again that is taking a of type pageable which page request is so we can say pr and that should be that so now we can do is we can go ahead and restart our application and head over to the browser and instead of going to the h2 console i'm going to go to api people and i'm going to do page zero and we're not actually gonna sort so page equals zero let's just do a size of two i'm gonna hit enter and now you see that we only get these two first two records so we have our first two records and then a whole bunch of other stuff so that page that page of persons what we get back is we get some content this includes the people but we also get a lot of information that may be useful to clients so here's this thing called pageable and then there's these other properties and then whether it was sorted but you could imagine returning some of this information to the client like is this the last page that's false that means that on a client where i had some navigation i can go ahead and enable the last button or the next button so i could say you know i can allow them to click keep kidding keep clicking next until last is true and then when that is is the case then i would disable the next button um so the same with first how many what is the size what number are we on how many of the total elements are there based on those total elements and the size how many total pages do we have so all this information is very useful to to the client so it really depends on what you want to return to the client in that case but this is all you really need to create some pagination so congratulations you just created an application that uses spring data jpa and you've built in some pagination so the client no longer needs to say give me all the records in your database they can be very specific with what page they want and how many records they want per page so again it really depends on the client needs now on what data you're going to return to the client so i really hope you enjoyed this again i'm going to follow this up with a graphql pagination example the reason i i kind of started with this is from the graphql side graphql doesn't care about your data layer so this data layer is what it is um the data you know even in this scenario rest the rest controller doesn't care about your data layer that data layer is independent the rest controller you're kind of defining you know how you're taking those request parameters in and then you're calling the repository which is going to do the same thing no matter whether using rest or graphql so i really hope you found this useful if you did please go ahead and leave me a thumbs up consider subscribing to the channel reaching out to me if you have any questions on this stuff or any tutorials that you'd like me to create if you can't tell i love doing this so with that i'll leave you and as always friends happy coding [Music]
Info
Channel: Dan Vega
Views: 6,724
Rating: undefined out of 5
Keywords: spring data jpa pagination, spring boot, spring data jpa, spring data jpa pagination and sorting, java, pagination, jpa, hibernate, spring, spring boot pagination and sorting, spring boot pagination example, spring boot tutorial, spring data, spring pagination tutorial, spring boot api pagination, spring pagination rest api, spring boot api paging
Id: oq-c3D67WqM
Channel Id: undefined
Length: 36min 45sec (2205 seconds)
Published: Fri May 13 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.